linux
一.基础知识服务器
客户端与服务器之间将展开一段结构化对话,叫协议。网络
在C语言中,若是写一个与网络通讯的程序,就须要新的数据流-套接字,套接字是双向的,既能够输入也能够输出数据结构
1.使用socket()函数建立一个套接字数据流socket
#include <sys/socket.h> int xxxx = socket(PF_INET, SOCK_STREAM, 0);
xxxx是套接字名字函数
套接字与客户端程序通讯,服务器须要经历,绑定端口,监听,接受链接,开始通讯,四个阶段spa
服务启动时,服务器会为每项服务分配一个端口,服务器启动时,须要告诉操做系统将要使用哪一个端口,这个过程叫作端口绑定。操作系统
2.这些代码将建立一个表示"互联网xxx端口"的套接字名code
#include <arpa/inet.h> struct sockeaddr_in xxxx; xxxx.sin_family = PF_INET; xxxx.sin+port = (in_port_t)htons(端口号); xxxx.sin_addr.s_addr = htonl(INADDR_ANY); int x = bind (套接字名字, (struct sockaddr * ) &xxxx, sizeof(name));
3.设置客户端链接服务器的排队数量blog
listen(套接字名字, xx)
xx为人数
在linux操做系统的/etc/services文件中能够查看经常使用服务使用的端口号
4.保存链接客户端的详细信息
struct sockaddr_storage xxxx; unsigned int address_size = sizeof(client_addr); int connect_d = accept(listener_d, (struct sockaddr *) &client_addr, &address_size);
套接字的输出方法:
二.使用send()函数写数据
send(套接字名称, xxxx, strlen(xxx), 0)
xxx和strlen(xxx)是消息和消息长度
0是高级参数填0便可
绑定端口有延时的解决办法,当使用某个端口绑定了套接字后,在接下来的30秒内,操做系统不容许任何程序绑定它,包括上次绑定这个端口的程序,咱们在绑定前设置套接字的某个选项,就能够解决这个问题了。
int reuse = 1; setsockopt(套接字名字, SQL_SOCKET, SO_REUSEADDR, (char * )&reuse, sizeof(int));
三.使用recv()函数读数据
recv (接收的描述符,字符变量的缓冲区,<要读取几个字节>, 0);
1.字符串不以\0结尾
2.当用户在客户端输入文本时用\r\n结尾
3.recv()将返回字符个数,若是发生错误就返回-1,若是客户端关闭链接就返回0
4.recv调用不必定能一次接收全部字符,须要配合循环,读取字符。
例如:
int read_in (int socket, char * buf, int len) { int c = recv(socket, buf, len, 0); }
四.为每一个客服端复制一份子进程
服务器在运行一份套接字进程给第一个用户时,没法运行第二个进程给第二个用户,所以使用fork()为每一个用户建立一个子进程。
服务器父进程只须要用主监听套接字,所以关闭副套接字,子进程需处理副套接字,关闭主监听套接字
五.建立ip地址套接字
1.客户端套接字的建立:
int xxx = socket (PF_INET, SOCK_STREAM, 0);
2.客户端和服务器处理套接字的方法不一样,服务器会把套接字绑定到本地端口,而客户端会把套接字链接至远程端口。
struct sockaddr_in xxx; memset(&xxx, 0, sizeof(xxx)); xxx.sin_family = PF_INET; xxx.sin_addr.s_addr = inet_addr("ip地址"); xxx.sin_port = htons(端口号); connect(xxx, (struct sockaddr *) &xxx, sizeof(xxx)); 链接套接字至远程端口
六.使用域名建立套接字
域名系统,计算机发送数据包时须要在地址一栏填写数字形式的ip地址,而dns能够把域名转化为ip地址
建立域名套接字:
#include<netdb.h> struct addrinfo * xxx; struct addrinfo xxxx; memset(&xxxx, 0, sizeof(xxxx)); xxxx.ai_family = PF_UNSPEC; xxxx.ai_socktype = SOCK_STREAM; getaddrinfo("域名", "端口", &xxxx, &xxx); getaddrinfo会在堆上建立一个xxx名字的新数据结构给定域名和端口号。
随后建立套接字
int x = socket(xxx->ai_family, xxx->ai_socktype, xxx->ai_protocal); connect(x, xxx->ai_addr, xxx->ai_addrlen); freeaddrinfo(xxx);链接之后删除地址数据