回射客户-服务器模型(2)
来源:互联网 发布:动漫头像制作软件 编辑:程序博客网 时间:2024/06/06 03:55
在上一节“回射客户-服务器模型(1)”中存在下面几个问题。
1.就是当服务器断开再立即重新开启时,需要重新绑定地址,而此时的服务器处于TIME_WAIT状态,在这种状态下,它是无法立即重新绑定的。
那么这种情况下,我们可以使用SO_REUSEADDR这个选项来解决这个问题。使用REUSEADDR选项就可以不必等待TIME_WAIT状态消失就可以立即重启服务器。
我们只需在服务器端的代码中使用setsockopt函数来开启一下REUSEADDR选项即可。
//...int on;if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)perror("setsockopt error");// 3. 绑定bindif(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)perror("bind error");//...这个时候我们再来断开服务器并立即重启一下.
第一次重启:
重启后又断开,服务器处于TIME_WAIT状态:
然后又立即重启服务器,没有问题:
但是请注意,SO_REUSEADDR选项只是保证服务器的开启不受TIME_WAIT状态的限制,但并不是说我们在启动一个服务器后,在没有断开的情况下还可以继续启动一个服务器。
2.不能处理多客户端的连接
原因:当一个客户端发来连接请求后,服务器断的套接口由主动状态变为被动状态,也就是开始接收连接并处理通信的细节问题,没办法再回到监听状态,也就无暇再去处理另一个客户端发送过来的连接请求。
那么要解决这个问题,我们就需要考虑到使用多进程。每当一个客户端发来连接请求,我们就让父进程fork出一个子进程去处理与客户端的通信细节,而父进程自己继续监听其他客户端的连接请求。
//...int conn; // 成功返回对等方的套接口while(1){if((conn = accept(lisenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)perror("accept error");printf("IP=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), htons(peeraddr.sin_port));pid_t pid = fork();if(pid < 0)perror("fork error");else if(pid > 0){//父进程处理//父进程不需要connclose(conn);}else{//子进程处理//子进程不需要监听close(listenfd);do_service(int conn);}}void do_service(int conn){char recvbuf[1024];while(1){memset(recvbuf, 0, sizeof(recvbuf));int ret = read(conn, recvbuf, sizeof(recvbuf));fputs(recvbuf, stdout);write(conn, recvbuf, ret);}}//...上述代码的改进能够解决连接多客户端的问题,看下面的演示结果:
3.但是上述的改进还存在一个问题就是服务器端不能捕捉到客户端的关闭,因此还需要进行改进。
那么我们的做法就是在do_service函数中,当服务器端从客户端后读取的字节数ret为0时,就表明客户端已经关闭了,并在捕捉到客户端关闭后,退出相应的子进程。
//...int conn; // 成功返回对等方的套接口while(1){if((conn = accept(lisenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)perror("accept error");printf("IP=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), htons(peeraddr.sin_port));pid_t pid = fork();if(pid < 0)perror("fork error");else if(pid > 0){//父进程处理//父进程不需要connclose(conn);}else{//子进程处理//子进程不需要监听close(listenfd);do_service(int conn);//客户端关闭后,就需要退出这个进程exit(EIXT_SUCCESS);}}void do_service(int conn){char recvbuf[1024];while(1){memset(recvbuf, 0, sizeof(recvbuf));int ret = read(conn, recvbuf, sizeof(recvbuf));if(ret == 0){printf("client close");break;}else if(ret == -1)ERR_EXIT("read error");fputs(recvbuf, stdout);write(conn, recvbuf, ret);}}//...
1 0
- 回射客户-服务器模型(2)
- 回射客户-服务器模型(1)
- 回射客户-服务器模型(3)
- 回射客户-服务器模型(4)
- 七、Linux网络编程-TCP客户/服务器模型、回射客户/服务器
- 用select改进回射客户-服务器模型
- 客户-服务器模型
- TCP客户/服务器模型
- SELECT 模型,多客户单服务器.
- 第一章 概述 1.8客户—服务器模型
- [C++]C++的客户/服务器模型
- socket多路复用的客户/服务器模型
- socket编程--TCP客户/服务器模型 (c/s)及基本函数
- UNIX网络编程——TCP客户/服务器(回射服务器)示例(多进程服务器)
- socke通信之三:阻塞版本的客户/服务器模型
- socket通信之四:多线程版本的客户/服务器模型
- socket通信之五:select多路复用的客户/服务器模型
- Socket学习之select多路复用的客户/服务器模型
- S188 Malaysia 20% DAILY FIRST DEPOSIT | Casino588
- ASP.NET Padding Oracle信息泄露漏洞
- python struct模块
- 使用alsa的API,设置和获得声音
- 时来天地皆同力,运去英雄不自由——北漂18年(84)
- 回射客户-服务器模型(2)
- 手机号在Java中的正则表达式
- iOS WKWebView高度自适应以及截获页面点击的url
- 网络请求okhttp框架
- Java反射机制详解
- Nginx Intro
- 地址窗口化扩展插件(AWE)要求'锁定内存页'特权,但在该进程的访问标记中当前未提供该权限。
- caffe--- 图片数据均值计算小工具
- 极光推送