linux环境下c语言书写socket服务器程序的步骤和注意事项课件_第1页
linux环境下c语言书写socket服务器程序的步骤和注意事项课件_第2页
linux环境下c语言书写socket服务器程序的步骤和注意事项课件_第3页
linux环境下c语言书写socket服务器程序的步骤和注意事项课件_第4页
linux环境下c语言书写socket服务器程序的步骤和注意事项课件_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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(sock0)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);/.MYP

4、ORT 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=%dn,ret);ret=-9;if(ret=listen(sock,100)0)/*listen()printf(liste

5、n 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,&namelen)=(n=recv(sockettemp,data_buf,MAXLINE,0)continue;elsesend(sockettemp,ch_send_back,strlen(ch_

6、send_back),0);close(sockettemp);break;close(sockettemp);printf(SOCKET END =n);exit(0);以上就是一个简单的socket服务器程序的框架了。2. 僵尸进程的处理。在程序运行之后,会出现如下的问题,就是fork了子进程之后,父进程便不再处理子进程,导致了僵尸进程的出现。如下图所示,会出现一个server01 的僵尸进程:为了避免这个问题的出现,现有四种方式可以处理。(1) 父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。执行wait()或waitpid()系统调用,则子进程在终止后会立即

7、把它在进程表中的数据返回给父进程,此时系统会立即删除该进入点。在这种情形下就不会产生defunct进程。(2) 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler。在子进程结束后,父进程会收到该信号,可以在handler中调用wait回收。(3) 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCLD, SIG_IGN)或signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号(4)fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那

8、么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收还要自己做。 具体的测试结果:(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 = wa

9、itpid(-1, &stat, WNOHANG);具体代码参考server02.c。试验结果还是比较满意,在单客户端访问时,效率几乎没什么影响,也不会产生僵尸进程,但是多个客户端,或者长期大量的链接的时候还是会产生僵尸进程。测试环境比较难以搭建。(3) 方法可以,而且简单容易实现,具体代码参考server03.c。(4) 没有测试,所以这里就只好不说了。3. 在测试的过程中发现了由于作者一开始对socket没有释放导致程序不能收发数据的现象。主要是在accept之后,跳出了fork之后没有close造成的。4. 日志文件是一个比较麻烦的问题。一般情况下,日志要写到一起,只能一个一个的进程对文

10、件进行操作,必然影响程序的并发性。这种情况下就需要建立一个缓冲区,将日志的数据保存到缓冲区中,然后在定时刷新,将缓冲区中的数据写到日志里面去。在windows下,作者比较喜欢使用一个动态链接库建立缓冲区的方法来实现,而在linux下,作者使用了一个比较简单的pipe(管道)的方法来实现这个。、具体的代码见server04.附录-代码Server01:/*/#include #include #include #include #include #include #include #include #include #include #include #define MAXLINE 4096in

11、t 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(sock0)printf(socket errorn);return 0;printf(soc

12、k-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(int);/bindif(ret=bind(sock,(struct sockaddr *)&server,sizeof(struct sockaddr)0)/

13、*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,ret);while(1)namelen=sizeof(struct sockaddr_in);/sockaddr_in:地址信息if(msgsock=accept(sock,(struct sockaddr *)&client,&namelen)=(n=recv(sockettemp

14、,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 #include #include #include #include #include #include #include #include #in

15、clude #include #define MAXLINE 4096void proc_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;in

16、t ret=-9;int client_id=0;/创建socketsock=socket(AF_INET,SOCK_STREAM,0);if(sock0)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_REU

17、SEADDR,(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=listen(sock,100)0)/*listen()printf(listen errorn);return 0; printf(listen-ret=%dn,ret);signal(SIGCHLD, pro

18、c_child);/signal(SIGCHLD, SIG_IGN);while(1)namelen=sizeof(struct sockaddr_in);/sockaddr_in:地址信息if(msgsock=accept(sock,(struct sockaddr *)&client,&namelen)=(n=recv(sockettemp,data_buf,MAXLINE,0)continue;elsesend(sockettemp,ch_send_back,strlen(ch_send_back),0);close(sockettemp);break;close(sockettemp)

19、;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 #include #include #include #include #include #include #include #include #include #include #define MAXLINE 4096void proc_

20、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=socket

21、(AF_INET,SOCK_STREAM,0);if(sock0)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(int);/

22、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,ret);/signal(SIGCHLD, proc_child);signal(SIGCHLD, SIG_IGN);while(1)na

23、melen=sizeof(struct sockaddr_in);/sockaddr_in:地址信息if(msgsock=accept(sock,(struct sockaddr *)&client,&namelen)=(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/fatherclo

24、se(msgsock);usleep(10);return 0;void proc_child(int SIGNO)int pid = -1;int stat;pid = waitpid(-1, &stat, WNOHANG);Server04/*/#include #include #include #include #include #include #include #include #include #include #include #define MAXLINE 4096#include logfile.hvoid proc_child(int SIGNO);int main()i

25、nt 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;/日志句柄int pipe_fd2;/管道char ch_log1000;/开启日志进程,打开日志文件,打开管道pFile=SetFileHandle(); if(pipe(pip

26、e_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.);/打开设备/创建socketsock=socket(AF_INET,SOCK_STREAM,0);if(sock0)printf(socket errorn);sprintf(ch_log,SOCK socket create Error!);/

27、WritePipe(pipe_fd1,ch_log);return 0;printf(sock-ret=%dn,sock);sprintf(ch_log,SOCK socket create Ok,socket=%d!,sock);/WritePipe(pipe_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_SOCKE

28、T ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(int);/bindif(ret=bind(sock,(struct sockaddr *)&server,sizeof(struct sockaddr)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);pri

29、ntf(bind-ret=%dn,ret);ret=-9;if(ret=listen(sock,100)0)/*listen()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(SIG

30、CHLD, SIG_IGN);while(1)printf(accept errorn);namelen=sizeof(struct sockaddr_in);/sockaddr_in:地址信息if(msgsock=accept(sock,(struct sockaddr *)&client,&namelen)=(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,

31、ch_log);/WritePipe(pipe_fd1,ch_log);send(sockettemp,ch_send_back,strlen(ch_send_back),0);sprintf(ch_log,SOCK socket sendback data=%s,ch_send_back);/WritePipe(pipe_fd1,ch_log);close(sockettemp);break;close(sockettemp);printf(SOCKET END =n);exit(0);else/fatherclose(msgsock);usleep(10);return 0;void proc_child(int

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论