Linux 进程间通信--信号、TCP粘包处理
来源:互联网 发布:windows epub 阅读器 编辑:程序博客网 时间:2024/06/05 02:47
Server
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#include <netinet/in.h> #include <signal.h>#define ERR_EXIT(m)\ do{\ perror(m);\ exit(EXIT_FAILURE);\ }while(0)struct packet{ int len; //包头 存放包体中数据的实际长度 char buf[1024];};/** 进程由于系统调用或者中断进入内核 在从内核空间返回到用户空间之前, 检查是否有信号产生,跳到用户态执行信号处理函数 linux 信号处理机制,请见另篇博文的浅析 信号产生的时候 ,不会立即响应,这是和中断不一样的一个地方*/void handler(int sig){ exit(0);}ssize_t readn(int fd,void * buf,size_t count){ size_t nleft = count; ssize_t nread; char * bufp = (char *)buf; while(nleft > 0) { nread = read(fd,bufp,nleft); if (nread == -1) { /** EINVAL 传给系统调用的参数不正确 EINTR 被信号中断 EFAULT 参数中有一指针指向无法存取的内存空间 信号会打断阻塞的系统调用。因此这里要判断一下。 */ if (errno == EINTR)//被信号中断 { continue; }else if (errno == EFAULT)//参数中有一指针指向无法存取的内存空间 会报"bad address"错误 { printf("参数有错误\n"); } return -1; }else if (nread == 0) //对方关闭了连接 { return count - nleft; }else{ bufp += nread; nleft -= nread; //剩余的字节数,如果大于0,继续读取 } } return count;}ssize_t writen(int fd, void * buf,size_t count){ size_t nleft = count; ssize_t nwrite ; char * bufp = (char *)buf; while(nleft > 0) { if((nwrite = write(fd,bufp,nleft)) < 0) { if (errno == EINTR) { continue; }else{ return -1; } }else if (nwrite == 0) { continue; }else{ bufp += nwrite; nleft -= nwrite; } } return count;}void do_server(int conn){ struct packet recvbuf; int n; while(1) { memset(&recvbuf,0,sizeof(recvbuf)); /** 先接收包头 */ int ret = readn(conn,&recvbuf.len,4); printf("packet header =%d \n",ret ); if (ret == -1) { ERR_EXIT("read"); }else if (ret < 4) { printf("client close\n"); break; } /** 接收包体 */ n = ntohl(recvbuf.len); ret = readn(conn,&recvbuf.buf,n); if (ret == -1) { ERR_EXIT("read"); }else if (ret < n) { printf("client close\n"); break; } fputs(recvbuf.buf,stdout); }}int main(int argc, char const *argv[]){ int listenfd; int ret; int conn; pid_t pid; listenfd = socket(AF_INET,SOCK_STREAM,0); if (listenfd == -1) { ERR_EXIT("socket"); } struct sockaddr_in servaddr; servaddr.sin_family = AF_INET; servaddr.sin_port = htons(6666); //主机字节序转换成网络字节序 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); int on = 1; ret = setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); if (ret == -1) { ERR_EXIT("setsockopt"); } ret = bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); if (ret == -1) { ERR_EXIT("bind"); } //SOMAXCONN = 三次握手已完成 + 三次握手为完成 ret = listen(listenfd,SOMAXCONN); if (ret == -1) { ERR_EXIT("listen"); } struct sockaddr_in clientaddr; socklen_t len = sizeof(clientaddr); conn = accept(listenfd,(struct sockaddr *)&clientaddr,&len); if (conn == -1) { ERR_EXIT("accept"); } pid = fork(); if (pid == 0) //子进程 { //标准C 写法 //signal(SIGUSR1,handler); struct sigaction act; act.sa_handler = handler; //将阻塞信号集全部置 0 sigemptyset(&act.sa_mask); act.sa_flags = 0; /** int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact); signum : 你要为那个信号注册捕捉函数 : SIGKILL、SIGSTOP 除外(这两个不能被捕捉、阻塞、忽略). act : 新设定的动作 oldact : 信号原来的动作.输出参数 返回值 : 0 成功 -1 失败 struct sigaction { 早期的函数 与下面的一个函数指针互斥 通过sa_mask来选择采用那种捕捉函数 void (*sa_handler)(int); void (*sa_sigaction)(int ,siginfo_t *,void *); 临时信号屏蔽字: 在执行捕捉函数的时候,设置阻塞其他信号, 退出捕捉函数后,还原原有的阻塞信号集 sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); }; */ int retval = sigaction(SIGUSR1,&act,NULL); if (retval == -1) { ERR_EXIT("sigaction"); } int n; struct packet sendbuf; memset(&sendbuf,0,sizeof(sendbuf)); while(fgets(sendbuf.buf,sizeof(sendbuf.buf),stdin) != NULL) { n = strlen(sendbuf.buf); sendbuf.len = htonl(n); writen(conn,&sendbuf,4 + n); memset(&sendbuf,0,sizeof(sendbuf)); } exit(0); }else if (pid > 0) { while(1) { printf("---do_server\n"); do_server(conn); break; } /** 向子进程发信号 */ kill(pid,SIGUSR1); exit(0); }else{ ERR_EXIT("fork"); } close(conn); close(listenfd); return 0;}
Client
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#include <netinet/in.h> #include <signal.h>#define ERR_EXIT(m)\ do{\ perror(m);\ exit(EXIT_FAILURE);\ }while(0)struct packet{ int len; //包头 存放包体中数据的实际长度 char buf[1024];};void handler(int sig){ exit(0);}ssize_t readn(int fd,void * buf,size_t count){ size_t nleft = count; ssize_t nread; char * bufp = (char *)buf; while(nleft > 0) { nread = read(fd,bufp,nleft); if (nread == -1) { /** EINVAL 传给系统调用的参数不正确 EINTR 被信号中断 EFAULT 参数中有一指针指向无法存取的内存空间 */ if (errno == EINTR)//被信号中断 { continue; }else if (errno == EFAULT)//参数中有一指针指向无法存取的内存空间 会报"bad address"错误 { printf("参数有错误\n"); } return -1; }else if (nread == 0) //对方关闭了连接 { return count - nleft; }else{ bufp += nread; nleft -= nread; //剩余的字节数,如果大于0,继续读取 } } return count;}ssize_t writen(int fd, void * buf,size_t count){ size_t nleft = count; ssize_t nwrite ; char * bufp = (char *)buf; while(nleft > 0) { if((nwrite = write(fd,bufp,nleft)) < 0) { if (errno == EINTR) { continue; }else{ return -1; } }else if (nwrite == 0) { continue; }else{ bufp += nwrite; nleft -= nwrite; } } return count;}void do_server(int conn){ struct packet recvbuf; int n; while(1) { memset(&recvbuf,0,sizeof(recvbuf)); /** 先接收包头 */ int ret = readn(conn,&recvbuf.len,4); if (ret == -1) { ERR_EXIT("read"); }else if (ret < 4) { printf("client close\n"); break; } /** 接收包体 */ n = ntohl(recvbuf.len); ret = readn(conn,&recvbuf.buf,n); if (ret == -1) { ERR_EXIT("read"); }else if (ret < n) { printf("client close\n"); break; } fputs(recvbuf.buf,stdout); }}int main(int argc, char const *argv[]){ int sock; int ret; pid_t pid; sock = socket(AF_INET,SOCK_STREAM,0); if (sock == -1) { ERR_EXIT("socket"); } struct sockaddr_in servaddr; servaddr.sin_family = AF_INET; servaddr.sin_port = htons(6666); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ret = connect(sock,(struct sockaddr *)&servaddr,sizeof(servaddr)); if (ret == -1) { ERR_EXIT("connect"); } pid = fork(); if (pid == 0) { //标准C 写法 //signal(SIGUSR1,handler); struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGUSR1,&act,NULL); int n; struct packet recvbuf; memset(&recvbuf,0,sizeof(recvbuf)); while(fgets(recvbuf.buf,sizeof(recvbuf.buf),stdin) != NULL) { n = strlen(recvbuf.buf); recvbuf.len = htonl(n); writen(sock,&recvbuf,4 + n); memset(&recvbuf,0,sizeof(recvbuf)); } exit(0); }else if (pid > 0) { struct packet recvbuf; memset(&recvbuf,0,sizeof(recvbuf)); while(1) { do_server(sock); break; } /** 向子进程发送信号 */ kill(pid,SIGUSR1); exit(0); }else{ ERR_EXIT("fork"); } close(sock); return 0;}
0 0
- Linux 进程间通信--信号、TCP粘包处理
- Linux进程间通信三之信号与处理
- linux进程间通信、异步信号处理机制
- 【linux系统编程】进程间通信:信号中断处理
- Linux进程间的通信——信号处理
- linux进程间通信方式之信号处理sigaction
- linux进程间通信方式之信号处理sigaction
- linux进程间通信方式之信号处理signal
- linux进程通信----信号的处理
- linux进程通信----信号的处理
- Linux 进程间通信 信号
- linux进程间通信--信号
- Linux进程间通信--信号
- Linux进程间通信 -- 信号
- Linux进程间通信-信号
- Linux进程间信号通信
- Linux 进程间通信 --- 信号通信 --- signal
- linux进程间通信-信号通信
- protoolkit开发工程图问题
- Android IPC之AIDL
- android开发之Fragment利用Bundle保存状态
- 常量和变量
- “南大软院大神养成计划“_第十六天的学习“
- Linux 进程间通信--信号、TCP粘包处理
- CentOS排错
- Unique Binary Search Trees
- 网络流 poj 1698
- synchronized的作用
- CCF201312-4有趣的数
- ios8 系统定位问题
- 仿微信读书软件原型设计
- 每天一篇,有助消化