Chinaunix首页 | 论坛 | 博客
  • 博客访问: 537761
  • 博文数量: 142
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1452
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-12 16:28
文章分类

全部博文(142)

文章存档

2016年(10)

2015年(60)

2014年(72)

我的朋友

分类: C/C++

2014-09-28 16:43:06

客户端与服务器端建立好TCP连接,如果此时服务器端关闭对应的socket,从而发送FIN报文给客户端,但是客户端仍然在对应的socket上发送数据,此时当服务器收到客户端的第一个write时,服务器发送RST报文告诉客户端自己的socket已经关闭,如果此时客户端仍然write数据给服务器,则客户端底层会触发发送SIGPIPE信号,该信号默认是终止进程,如果不想被终止,则修改信号处理函数。
tcpserver.c

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <signal.h>
  5. #include <sys/socket.h>
  6. #include <sys/types.h>
  7. #include <sys/wait.h>
  8. #include <errno.h>
  9. #include <netinet/in.h>
  10. #include <arpa/inet.h>
  11. #include <sys/wait.h>
  12. #include <strings.h>
  13. #include "readn.h"


  14. void str_echo(int fd)
  15. {
  16.     int n;
  17.     char recvline[MAXLINE];
  18. again:
  19.     while((n = read(fd,recvline,MAXLINE))>0) {
  20.         writen(fd,recvline,n);
  21.     }
  22.     if(n < 0 && errno == EINTR) {
  23.         goto again;
  24.     }else if (n < 0) {
  25.         printf("read error\n");
  26.     }
  27. }
  28. void sig_proc(int signo)
  29. {
  30.     int status;
  31.     pid_t pid;
  32.     if(signo == SIGCHLD) {
  33.        while((pid = wait(&status)) > 0)
  34.            printf("pid %d terminated\n",pid);
  35.        printf("exit.....pid=%d,selfpid=%d,ppid=%d\n",pid,getpid(),getppid());
  36.     }
  37. }
  38. int main(int argc,char *argv[])
  39. {
  40.     int ret = 0;
  41.     int listen_fd;
  42.     int conn_fd;
  43.     struct sockaddr_in server_addr;
  44.     struct sockaddr_in client_addr;
  45.     pid_t pid;
  46.     socklen_t len;

  47.     listen_fd = socket(AF_INET,SOCK_STREAM,0);

  48.     if(listen_fd < 0) {
  49.         printf("socket error\n");
  50.         return -1;
  51.     }

  52.     bzero(&server_addr,sizeof(struct sockaddr_in));

  53.     server_addr.sin_family = AF_INET;
  54.     server_addr.sin_port = htons(10000);
  55.     //server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  56.     ret = inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);
  57.     if(ret < 0) {
  58.         printf("inet_pton error\n");
  59.         close(listen_fd);
  60.         return ret;
  61.     }else if(ret == 0) {
  62.         printf("the second parameter of inet_addr is null\n");
  63.     }

  64.     if(bind(listen_fd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)) == -1) {
  65.             printf("bind error\n");
  66.             close(listen_fd);
  67.             return -1;
  68.     }
  69.     

  70.     if(listen(listen_fd,1024) == -1) {
  71.         printf("listen error\n");
  72.         close(listen_fd);
  73.         return -1;
  74.     }
  75.     signal(SIGCHLD,sig_proc);

  76.     for(;;) {
  77.         len = sizeof(client_addr);
  78.         conn_fd = accept(listen_fd,(struct sockaddr*)&client_addr,&len);
  79.         if(conn_fd < 0) {
  80.             printf("accept error,errno=%d\n",errno);
  81.             if(errno == EINTR)
  82.                 continue;
  83.             return -1;
  84.         }

  85.         pid = fork();

  86.         if(pid < 0) {
  87.             printf("fork error\n");
  88.             return -1;
  89.         }else if(pid == 0) {
  90.             close(listen_fd);
  91.             /*TODO::handle on conn_fd*/
  92.             str_echo(conn_fd);
  93.             exit(0);
  94.         }
  95.         close(conn_fd);
  96.    }

  97.     return 0;
  98. }

tcpclient.c

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <sys/socket.h>
  5. #include <string.h>
  6. #include <sys/types.h>
  7. #include <arpa/inet.h>
  8. #include <errno.h>
  9. #include <signal.h>
  10. #include "readn.h"
  11. void str_cli(FILE *fp,int fd)
  12. {
  13.     int ret;
  14.     char sendline[1024], recvline[1024];
  15.     while(fgets(sendline,1024,fp)) {
  16.         writen(fd,sendline,1);
  17.         sleep(1);
  18.         ret = writen(fd,sendline+1,strlen(sendline)-1);
  19.         if(ret < 0)
  20.             printf("writen error in str_cli,ret = %d,errno=%d\n",ret,errno);
  21.         memset(recvline,0,sizeof(recvline));
  22.         if(0 == readline(fd,recvline,sizeof(recvline))) {
  23.             printf("server terminated\n");
  24.             return;
  25.         }
  26.         fputs(recvline,stdout);
  27.     }
  28. }

  29. void sig_pipe(int signo)
  30. {
  31.     printf("catch sigpipe\n");
  32. }

  33. int main(int argc,char* argv[])
  34. {
  35.     int fd;
  36.     struct sockaddr_in server_addr;
  37.     int ret = 0;

  38.     fd = socket(AF_INET,SOCK_STREAM,0);

  39.     if(fd < 0) {
  40.         printf("socket error\n");
  41.         return -1;
  42.     }

  43.     bzero(&server_addr,sizeof(struct sockaddr_in));

  44.     server_addr.sin_family = AF_INET;
  45.     ret = inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr);

  46.     if(ret < 0) {
  47.         printf("inet_pton error\n");
  48.         return -1;
  49.     }else if(ret == 0) {
  50.         printf("the second parameter of inet_pton is NULL\n");
  51.     }
  52.     server_addr.sin_port = htons(10000);

  53.     ret = connect(fd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));
  54.     if(ret < 0) {
  55.         printf("connect error\n");
  56.         return -1;
  57.     }
  58.     signal(SIGPIPE,sig_pipe);
  59.     str_cli(stdin,fd);

  60.     return 0;
  61. }


编译运行:
gwwu@hz-dev2.wgw.com:~/test/socket>gcc -g readn.c tcpclient.c -o tcpclient -Wall
gwwu@hz-dev2.wgw.com:~/test/socket>gcc -g readn.c tcpserver.c -o tcpserver -Wall

1)运行服务器
  ./tcpserver
2)运行客户端
 ./tcpclient
3)在客户端敲入任一字符,客户端可以回显
4)使用ps命令查找服务器子进程ID,并kill之
 gwwu@hz-dev2.wgw.com:~/codes/ipv6_8_12>ps -t pts/4 -o pid,ppid,tty,stat,args,wchan
  PID  PPID TT       STAT COMMAND                     WCHAN
20573 31168 pts/4    S+   ./tcpserver                 inet_csk_accept
20578 20573 pts/4    S+   ./tcpserver                 sk_wait_data
31168 31167 pts/4    Ss   -bash                       wait
kill服务器子进程
kill -9  20578 
5)在客户端输入任一字符,客户端进程由于收到SIGPIPE信号而退出。
abc                            -----输入abc
catch sigpipe
writen error in str_cli,ret = -1,errno=32
server terminated






阅读(775) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~