




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、在linux下用c语言编写socket服务器。首先分析需要解决的问题:1. Socket的处理机制。一般的处理方法是在服务端socket初始化和建立监听之后,开启一个while死循环。不断接受传递过来的socket链接请求,如果链接请求成功,开启一个子进程fork,在子进程中对socket进行处理。处理完毕之后,子进程结束退出。经本人测试研究发现了1中框架的几个问题,比较的突出。具体如下。2. 开启子进程容易产生僵尸进程。一开始的代码不完善,在子进程中exit后,父进程没有对其进行操作,导致了子进程成为僵尸进程,处理此问题有3种方法,将在后面进行详细说明。3. Socket的处理容易不严谨,导
2、致程序奔溃。Socket的处理要严谨,否则在程序的运行过程中会出现socket资源不能释放的问题。4. 日志文件的处理。在多进程(线程)处理中会面临一个日志文件不可共享写的问题。本文中的代码均为作者测试使用过,在本文的最后会附上所有代码,如有疑问或者需要可以联系作者,qq:398810897。具体问题分析:1. socket的基本框架(代码文件为server01.c)。在windows和linux下的socket编程基本上是一样的,没有多大的差别,都是遵循着 创建socket、定义socket(socket赋值)、绑定socket、开启监听、socket收发、关闭socket的流程来的,在wi
3、ndows下一开始还需要初始化socket版本,在这里主要针对的linux环境下的socket,所以windows下的东西就不细说了。创建可以收发数据的socket的必须的步骤如下:/创建socketsock=socket(AF_INET,SOCK_STREAM,0);if(sock<0)printf("socket errorn");return 0;printf("sock-ret=%dn",sock);/网络字节序server.sin_family=AF_INET;server.sin_addr.s_addr=INADDR_ANY;serve
4、r.sin_port=htons(6000);/.MYPORT bzero(&(server.sin_zero),8);setsockopt(sock,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(int);/bindif(ret=bind(sock,(struct sockaddr *)&server,sizeof(struct sockaddr)<0)/*bind()printf("bind errorn");return 0;printf("bind-ret=%
5、dn",ret);ret=-9;if(ret=listen(sock,100)<0)/*listen()printf("listen errorn");return 0; printf("listen-ret=%dn",ret);在socket的创建以及初始化之后,做一个while(1)的死循环进行和客户端的链接。while(1)namelen=sizeof(struct sockaddr_in);/sockaddr_in:地址信息if(msgsock=accept(sock,(struct sockaddr *)&client,
6、&namelen)<0)/*accept()printf("accept errorn");continue;else。如果有客户端链接成功,即开启一个子进程来处理相关的流程。在else中处理这个问题,在这里把else里面的代码贴出来。elseprintf("socket accept from sock=%d,ip=%s,port=%dn",msgsock,inet_ntoa(client.sin_addr),client.sin_port);printf("SOCKET BEGIN=n");if(!fork()/ch
7、ildint sockettemp=msgsock;while(1)char data_bufMAXLINE;/socket recv char ch_send_back300;/socket backint n=0;memset(data_buf,0,MAXLINE);if(0>=(n=recv(sockettemp,data_buf,MAXLINE,0)continue;elsesend(sockettemp,ch_send_back,strlen(ch_send_back),0);close(sockettemp);break;close(sockettemp);printf(&q
8、uot;SOCKET END =n");exit(0);以上就是一个简单的socket服务器程序的框架了。2. 僵尸进程的处理。在程序运行之后,会出现如下的问题,就是fork了子进程之后,父进程便不再处理子进程,导致了僵尸进程的出现。如下图所示,会出现一个server01 <defunct>的僵尸进程:为了避免这个问题的出现,现有四种方式可以处理。(1) 父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。执行wait()或waitpid()系统调用,则子进程在终止后会立即把它在进程表中的数据返回给父进程,此时系统会立即删除该进入点。在这种情形下就
9、不会产生defunct进程。(2) 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler。在子进程结束后,父进程会收到该信号,可以在handler中调用wait回收。(3) 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCLD, SIG_IGN)或signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号(4)fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收还要自
10、己做。 具体的测试结果:(1) 方法是可以避免僵尸进程的产生,但是效率很低,每一次fork了子进程,父进程都要等到子进程exit了才能继续运行,不适合在并发量很高的服务器程序上使用。(2) 在程序中定义一个signal的函数void proc_child(int SIGNO);然后在server监听了之后,和客户端链接之前,调用此函数signal(SIGCHLD, proc_child);函数的具体实现如下:void proc_child(int SIGNO)int pid = -1;int stat;pid = waitpid(-1, &stat, WNOHANG);具体代码参考se
11、rver02.c。试验结果还是比较满意,在单客户端访问时,效率几乎没什么影响,也不会产生僵尸进程,但是多个客户端,或者长期大量的链接的时候还是会产生僵尸进程。测试环境比较难以搭建。(3) 方法可以,而且简单容易实现,具体代码参考server03.c。(4) 没有测试,所以这里就只好不说了。3. 在测试的过程中发现了由于作者一开始对socket没有释放导致程序不能收发数据的现象。主要是在accept之后,跳出了fork之后没有close造成的。4. 日志文件是一个比较麻烦的问题。一般情况下,日志要写到一起,只能一个一个的进程对文件进行操作,必然影响程序的并发性。这种情况下就需要建立一个缓冲区,将
12、日志的数据保存到缓冲区中,然后在定时刷新,将缓冲区中的数据写到日志里面去。在windows下,作者比较喜欢使用一个动态链接库建立缓冲区的方法来实现,而在linux下,作者使用了一个比较简单的pipe(管道)的方法来实现这个。、具体的代码见server04.附录-代码Server01:/*/#include <stdio.h>#include <stdlib.h>#include <memory.h>#include <errno.h>#include <fcntl.h>#include <sys/socket.h>#inc
13、lude <sys/wait.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#include <signal.h>#define MAXLINE 4096int main()int sock;/server socketstruct sockaddr_in server;/server socketaddr_instruct sockaddr_in client;char msgsock;/client socketint namelen;/sock
14、et addr lengthint bReuseaddr=1;int ret=-9;int client_id=0;/创建socketsock=socket(AF_INET,SOCK_STREAM,0);if(sock<0)printf("socket errorn");return 0;printf("sock-ret=%dn",sock);/网络字节序server.sin_family=AF_INET;server.sin_addr.s_addr=INADDR_ANY;server.sin_port=htons(6000);/.MYPORT b
15、zero(&(server.sin_zero),8);setsockopt(sock,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(int);/bindif(ret=bind(sock,(struct sockaddr *)&server,sizeof(struct sockaddr)<0)/*bind()printf("bind errorn");return 0;printf("bind-ret=%dn",ret);ret=-9;if(ret=liste
16、n(sock,100)<0)/*listen()printf("listen errorn");return 0; printf("listen-ret=%dn",ret);while(1)namelen=sizeof(struct sockaddr_in);/sockaddr_in:地址信息if(msgsock=accept(sock,(struct sockaddr *)&client,&namelen)<0)/*accept()printf("accept errorn");continue;else
17、printf("socket accept from sock=%d,ip=%s,port=%dn",msgsock,inet_ntoa(client.sin_addr),client.sin_port);printf("SOCKET BEGIN=n");if(!fork()/childint sockettemp=msgsock;while(1)char data_bufMAXLINE;/socket recv char ch_send_back300;/socket backint n=0;memset(data_buf,0,MAXLINE);if(
18、0>=(n=recv(sockettemp,data_buf,MAXLINE,0)continue;elsesend(sockettemp,ch_send_back,strlen(ch_send_back),0);close(sockettemp);break;close(sockettemp);printf("SOCKET END =n");exit(0);else/fatherclose(msgsock);usleep(10);return 0;Server02:/*/#include <stdio.h>#include <stdlib.h>
19、;#include <memory.h>#include <errno.h>#include <fcntl.h>#include <sys/socket.h>#include <sys/wait.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#include <signal.h>#define MAXLINE 4096void proc_child(int SIGNO)int pid = -1;int
20、stat;pid = waitpid(-1, &stat, WNOHANG);int main()int sock;/server socketstruct sockaddr_in server;/server socketaddr_instruct sockaddr_in client;char msgsock;/client socketint namelen;/socket addr lengthint bReuseaddr=1;int ret=-9;int client_id=0;/创建socketsock=socket(AF_INET,SOCK_STREAM,0);if(so
21、ck<0)printf("socket errorn");return 0;printf("sock-ret=%dn",sock);/网络字节序server.sin_family=AF_INET;server.sin_addr.s_addr=INADDR_ANY;server.sin_port=htons(6000);/.MYPORT bzero(&(server.sin_zero),8);setsockopt(sock,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof
22、(int);/bindif(ret=bind(sock,(struct sockaddr *)&server,sizeof(struct sockaddr)<0)/*bind()printf("bind errorn");return 0;printf("bind-ret=%dn",ret);ret=-9;if(ret=listen(sock,100)<0)/*listen()printf("listen errorn");return 0; printf("listen-ret=%dn",re
23、t);signal(SIGCHLD, proc_child);/signal(SIGCHLD, SIG_IGN);while(1)namelen=sizeof(struct sockaddr_in);/sockaddr_in:地址信息if(msgsock=accept(sock,(struct sockaddr *)&client,&namelen)<0)/*accept()printf("accept errorn");continue;elseprintf("socket accept from sock=%d,ip=%s,port=%d
24、n",msgsock,inet_ntoa(client.sin_addr),client.sin_port);printf("SOCKET BEGIN=n");if(!fork()/childint sockettemp=msgsock;while(1)char data_bufMAXLINE;/socket recv char ch_send_back300;/socket backint n=0;memset(data_buf,0,MAXLINE);if(0>=(n=recv(sockettemp,data_buf,MAXLINE,0)continue;
25、elsesend(sockettemp,ch_send_back,strlen(ch_send_back),0);close(sockettemp);break;close(sockettemp);printf("SOCKET END =n");exit(0);else/fatherclose(msgsock);usleep(10);return 0;void proc_child(int SIGNO)int pid = -1;int stat;pid = waitpid(-1, &stat, WNOHANG);Server03:/*/#include <st
26、dio.h>#include <stdlib.h>#include <memory.h>#include <errno.h>#include <fcntl.h>#include <sys/socket.h>#include <sys/wait.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#include <signal.h>#define MAXLINE 4096void proc_
27、child(int SIGNO)int pid = -1;int stat;pid = waitpid(-1, &stat, WNOHANG);int main()int sock;/server socketstruct sockaddr_in server;/server socketaddr_instruct sockaddr_in client;char msgsock;/client socketint namelen;/socket addr lengthint bReuseaddr=1;int ret=-9;int client_id=0;/创建socketsock=so
28、cket(AF_INET,SOCK_STREAM,0);if(sock<0)printf("socket errorn");return 0;printf("sock-ret=%dn",sock);/网络字节序server.sin_family=AF_INET;server.sin_addr.s_addr=INADDR_ANY;server.sin_port=htons(6000);/.MYPORT bzero(&(server.sin_zero),8);setsockopt(sock,SOL_SOCKET ,SO_REUSEADDR,(c
29、onst char*)&bReuseaddr,sizeof(int);/bindif(ret=bind(sock,(struct sockaddr *)&server,sizeof(struct sockaddr)<0)/*bind()printf("bind errorn");return 0;printf("bind-ret=%dn",ret);ret=-9;if(ret=listen(sock,100)<0)/*listen()printf("listen errorn");return 0; pri
30、ntf("listen-ret=%dn",ret);/signal(SIGCHLD, proc_child);signal(SIGCHLD, SIG_IGN);while(1)namelen=sizeof(struct sockaddr_in);/sockaddr_in:地址信息if(msgsock=accept(sock,(struct sockaddr *)&client,&namelen)<0)/*accept()printf("accept errorn");continue;elseprintf("socket
31、accept from sock=%d,ip=%s,port=%dn",msgsock,inet_ntoa(client.sin_addr),client.sin_port);printf("SOCKET BEGIN=n");if(!fork()/childint sockettemp=msgsock;while(1)char data_bufMAXLINE;/socket recv char ch_send_back300;/socket backint n=0;memset(data_buf,0,MAXLINE);if(0>=(n=recv(socket
32、temp,data_buf,MAXLINE,0)continue;elsesend(sockettemp,ch_send_back,strlen(ch_send_back),0);close(sockettemp);break;close(sockettemp);printf("SOCKET END =n");exit(0);else/fatherclose(msgsock);usleep(10);return 0;void proc_child(int SIGNO)int pid = -1;int stat;pid = waitpid(-1, &stat, WNO
33、HANG);Server04/*/#include <stdio.h>#include <stdlib.h>#include <memory.h>#include <errno.h>#include <fcntl.h>#include <sys/socket.h>#include <sys/wait.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#include <signal.h&g
34、t;#define MAXLINE 4096#include "logfile.h"void proc_child(int SIGNO);int main()int sock;/server socketstruct sockaddr_in server;/server socketaddr_instruct sockaddr_in client;char msgsock;/client socketint namelen;/socket addr lengthint bReuseaddr=1;int ret=-9;int client_id=0;FILE * pFile;
35、/日志句柄int pipe_fd2;/管道char ch_log1000;/开启日志进程,打开日志文件,打开管道pFile=SetFileHandle(); if(pipe(pipe_fd)<0) printf("pipe create errorn"); return -1; if(!fork()/开启日志进程while(1)WriteLog(pipe_fd0,NULL,pFile);usleep(100);/100ms刷新一次日志else/WritePipe(pipe_fd1,"LOG-LOGlog process begin.");/打开设备
36、/创建socketsock=socket(AF_INET,SOCK_STREAM,0);if(sock<0)printf("socket errorn");sprintf(ch_log,"SOCK socket create Error!");/WritePipe(pipe_fd1,ch_log);return 0;printf("sock-ret=%dn",sock);sprintf(ch_log,"SOCK socket create Ok,socket=%d!",sock);/WritePipe(pip
37、e_fd1,ch_log);/网络字节序server.sin_family=AF_INET;server.sin_addr.s_addr=INADDR_ANY;server.sin_port=htons(6000);/.MYPORT bzero(&(server.sin_zero),8);setsockopt(sock,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(int);/bindif(ret=bind(sock,(struct sockaddr *)&server,sizeof(struct so
38、ckaddr)<0)/*bind()printf("bind errorn");sprintf(ch_log,"SOCK socket bind Error!");/WritePipe(pipe_fd1,ch_log);return 0;sprintf(ch_log,"SOCK socket bind Ok!");/WritePipe(pipe_fd1,ch_log);printf("bind-ret=%dn",ret);ret=-9;if(ret=listen(sock,100)<0)/*listen
39、()printf("listen errorn");sprintf(ch_log,"SOCK socket listen Error!");/WritePipe(pipe_fd1,ch_log);return 0; printf("listen-ret=%dn",ret); sprintf(ch_log,"SOCK socket listen Ok!");/WritePipe(pipe_fd1,ch_log);/signal(SIGCHLD, proc_child);signal(SIGCHLD, SIG_IGN)
40、;while(1)printf("accept errorn");namelen=sizeof(struct sockaddr_in);/sockaddr_in:地址信息if(msgsock=accept(sock,(struct sockaddr *)&client,&namelen)<0)/*accept()printf("accept errorn");continue;elsesprintf(ch_log,"SOCK get connect from sock=%d,ip=%s,port=%d",msgs
41、ock,inet_ntoa(client.sin_addr),client.sin_port);/WritePipe(pipe_fd1,ch_log);printf("socket accept from sock=%d,ip=%s,port=%dn",msgsock,inet_ntoa(client.sin_addr),client.sin_port);printf("SOCKET BEGIN=n");if(!fork()/childint sockettemp=msgsock;while(1)char data_bufMAXLINE;/socket recv char ch_send_back300;/socket backint n=0;memset(data_buf,0,MAXLINE);if(0>=(n=recv(sockettemp,data_buf,MAXLINE,0)continue;elsesprintf(ch_log,"SOCK recv data from sock=%d,data=%s",sockettemp,data_buf);/WritePipe(pipe_fd1
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 酒店业智能化升级改造服务协议
- 2024年度宁夏回族自治区二级造价工程师之建设工程造价管理基础知识通关提分题库(考点梳理)
- 食品行业产品质量安全问题处理流程
- 部编教材二年级上册道德教育课程设计
- 建筑工程技术专业毕业实习报告范文
- 高校心理健康与艾滋病防治计划
- 企业心理健康培训服务流程
- 学校水电气设备维修报修流程
- 国学与心理健康的心得体会
- QS认证现场审核不合格项整改报告范文
- 课件:《科学社会主义概论(第二版)》第五章
- DB36∕T 1720-2022 牧草裹包青贮技术规程
- 基于BIM技术的建筑工程安全管理应用与探讨
- 2025年河南测绘职业学院高职单招职业技能测试近5年常考版参考题库含答案解析
- 2025-2030年中国抗哮喘市场现状调研及投资发展潜力分析报告
- 2024年河南艺术职业学院高职单招职业适应性测试历年参考题库含答案解析
- 贝壳好赞服务协议书
- 大数据与人工智能营销知到智慧树章节测试课后答案2024年秋南昌大学
- 第20课 清朝君主专制的强化(导学案)(原卷版)
- VR游戏中心:虚拟现实的娱乐新趋势
- T-CSUS 69-2024 智慧水务技术标准
评论
0/150
提交评论