网络上的客户端与服务器是如何建立连接的?这之间又有着怎样的协议来完成这一系列的连接步骤?
Internet使用的主流协议族TCP/IP协议族是一个分层、多协议的通信系统,自底向上的四层分别为应用层、传输层、网络层以及数据链路层,每一层都有若干协议。
传输层为上层提供两种协议:TCP和UDP。TCP提供面向连接的,可靠的流式服务,而UDP则提供无连接的,不可靠的数据报服务。
进行网络通信需要借助于网络编程API(socket),在服务器端,首先我们要创建一个套接字socket,然后定义一个socket地址(结构体sockaddr),然后命名socket,然后创建监听socket,然后就是接受连接、接收数据,发送数据,关闭连接;在客户端,我们创建套接字socket,接着定义socket地址,然后发起连接,发送数据,接收数据,关闭连接。
socket套接字是一个文件描述符,返回值为-1,说明调用socket系统失败;成功则返回一个文件描述符。代码:
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd != -1);
定义一个socket地址用来存放服务器所使用的协议族、ip地址以及端口号。值得注意的是,其中的端口号和ip地址要转换成网络字节序。代码:
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;//地址族
saddr.sin_port = htonl(6000);//网络字节序的端口号
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");//网络字节序的ip
命名socket是指将socket与socket地址绑定。在服务器中,只有命名socket之后客户端才知道如何连接它,但是客户端则不需要命名socket。代码如下:
int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res != -1);
创建一个监听socket队列,存放待处理的客户连接。代码如下:
listen(sockfd,5);//5表示内核监听队列的最大长度
从listen监听队列中接受一个连接,代码如下:
int len = sizeof(caddr);
int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
如果连接成功,客户端就可以和服务器端进行交互了,在这里演示发送数据与接收数据,代码如下:
if(c > 0)//接收数据
{
char buff[128] = {0};
recv(c,buff,127,0);
}
printf("buff = %s\n",buff);
send(c,"ok",2,0);//发送数据
在客户端要向服务器端发起连接,代码如下:
int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res != -1);
关闭连接,代码如下:
close(sockfd);