回射客户-服务器模型(1)

来源:互联网 发布:搞笑特效软件 编辑:程序博客网 时间:2024/06/06 00:21

最近在学习socket编程,根据自己的学习过程及学习笔记,下面来梳理一下如何实现一个简单的回射客户-服务器模型,也借此来熟悉一下socket、bind、listen、accept、connect这些函数的使用。

简单的回射客户/服务器模型



下面先看一下一个客户/服务器模型的框架图。


可以看到,服务器创建过程一般是:

1)创建套接字,使用socket函数,这个时候的套接字是主动套接字

2)初始化服务器端地址,并使用bind函数将套接口与该地址进行绑定;

3)监听,使用listen函数,将套接口从close状态转为监听状态才能够接收客户端发起的连接,同时经过监听之后,服务器端的套接字从主动状态(发起连接)变为被动状态(接收连接);

4)等待接收连接,accept函数,使用该函数后,服务器端一直处于阻塞状态,直到客户端的连接到达;

5)等客户端的连接到达后,双方开始进行通信(读写数据);


客户端创建的过程就相对简单了:

1)创建套接字;

2)使用connect函数发起连接(过程中要经过三次握手);

3)连接成功,双方相互进行通信;


下面以代码的方式具体说明每一步骤的实现。

服务器端

// 1. 创建套接字int listenfd;if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)perror("socket create error");// 2. 初始化地址struct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;//地址族servaddr.sin_port = htons(5188); //端口servaddr.sin_addr.s_addr = htonl(INADDR_ANY);// 表示本机的任意地址,当然也可以自己指定//servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 3. 绑定bindif(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)perror("bind error");// 4. 监听listenif(listen(listenfd, SOMAXCONN) < 0)//第二个参数表示每一个端口的最大监听队列长度perror("listen error");// 5. 接收连接// 在接收连接前,先定义一个地址结构,用来保存对等方的地址struct sockaddr_in peeraddr;socklen_t peerlen = sizeof(peeraddr);memset(&peeraddr, 0, peerlen);int conn; // 成功返回对等方的套接口if((conn = accept(lisenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)perror("accept error");//输出客户端的地址和端口(仅测试用)printf("IP=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));// 至此,双方连接已完成,可以进行通信char recvbuf[1024];while(1){memset(recvbuf, 0, sizeof(recvbuf));int ret = read(conn, recvbuf, sizeof(recvbuf));fputs(recvbuf, stdout);//再回射给客户端write(conn, recvbuf, ret);}//关闭套接口close(lisenfd);close(conn);

需要对上述的一些步骤做一些说明:

1)在初始化地址的时候,服务器端地址可以指定为具体某一IP,也可以是INADDR_ANY。这里建议选用INADDR_ANY参数,表示地址0.0.0.0,也就是不确定的地址,或“所有地址”、“任意地址”。如果你的服务器有多个网卡,你要在5188这个端口上监听,所有发送到服务器的这个端口,不管是哪个网卡/哪个IP地址接收到的数据,都可以进行处理。

2)关于listen函数中的第二个参数。每一个处于监听状态的端口,都要自己的监听队列,那么该参数就指定了监听队列的长度。我们可以自己指定一个正整数,也可以使用参数SOMANCONN,它表示每个端口的最大监听队列长度。


客户端:

// 1. 创建套接字int sock;if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)perror("socket create error");// 2. 初始化一个你要连接的对方的地址struct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr);servaddr.sin_family = AF_INET;servaddr.sin_port = htons(5188);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 3. 发起连接if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)perror("connect error");// 4. 进行通信(读写数据)char recvbuf[1024] = {0};char sendbuf[1024] = {0};while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL){//发送数据(请求连接)write(sock, sendbuf, strlen(sendbuf));//读取服务器端回射来的数据read(sock, recvbuf, sizeof(recvbuf));fputs(recvbuf, stdout);//每次读取完毕需要清空缓冲区memset(sendbuf, 0, sizeof(sendbuf));memset(recvbuf, 0, sizeof(recvbuf));}//关闭套接口close(sock);


1 0
原创粉丝点击