这个例子是简单的演示。先贴代码。
服务端:
#include<stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> #include<signal.h> #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while (0) void handler(int sig) { printf("recv a sig=%d\n", sig); exit(EXIT_SUCCESS); } int main(void) { int listenfd; //被动套接字(文件描述符),即只可以accept if ((listenfd = socket(AF_INET, SOCK_STREAM,0)) < 0) ERR_EXIT("socket error"); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); int on = 1; if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) ERR_EXIT("setsockopt error"); if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) ERR_EXIT("bind error"); if (listen(listenfd, SOMAXCONN) < 0) //listen应在socket和bind之后,而在accept之前 ERR_EXIT("listen error"); struct sockaddr_in peeraddr; //传出参数 socklen_t peerlen = sizeof(peeraddr); //传入传出参数,必须有初始值 int conn; // 已连接套接字(变为主动套接字,即可以主动connect) if ((conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen)) < 0) ERR_EXIT("accept error"); printf("recv connect ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port)); pid_t pid; pid = fork(); if (pid == -1) ERR_EXIT("fork error"); if (pid == 0)//此子进程用于接收终端输入并且发送给客户端 { signal(SIGUSR1, handler); char sendbuf[1024] = {0}; while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL) { write(conn, sendbuf, strlen(sendbuf)); memset(sendbuf, 0, sizeof(sendbuf)); } exit(EXIT_SUCCESS); } else //此进程用于接收客户端信息 { char recvbuf[1024]; while (1) { memset(recvbuf, 0, sizeof(recvbuf)); int ret = read(conn, recvbuf, sizeof(recvbuf)); if (ret == -1) ERR_EXIT("read error"); else if (ret == 0) { printf("peer close\n"); break; } fputs(recvbuf, stdout); } kill(pid, SIGUSR1); //父进程退出时发送信号给子进程 exit(EXIT_SUCCESS); } }
客户端:
#include<sys/types.h> #include<sys/socket.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> #include<stdio.h> #define ERR_EXIT(m)\ do{\ perror(m);\ exit(EXIT_FAILURE);\ }while(0) int main(void) { int sock; if((sock = socket(AF_INET,SOCK_STREAM,0)) < 0) ERR_EXIT("socket error"); struct sockaddr_in servaddr; memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if(connect(sock,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0) ERR_EXIT("connect error"); pid_t pid; pid = fork(); if(pid == -1) ERR_EXIT("fork error"); if(pid == 0)//此子进程用于发送数据 { char sendbuf[1024] = {0}; while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL) { write(sock,sendbuf,strlen(sendbuf)); memset(sendbuf,0,sizeof(sendbuf)); } exit(EXIT_SUCCESS); } else//此进程用于接收数据 { char recvbuf[1024] = {0}; while(1) { int ret = read(sock,recvbuf,sizeof(recvbuf)); if(ret == -1) ERR_EXIT("read error"); else if (ret == 0) { printf("client close\n"); break; } fputs(recvbuf,stdout); memset(recvbuf,0,sizeof(recvbuf)); } exit(EXIT_SUCCESS); } }
服务端使用了kill来发送信号关闭子进程,但是客户端没有这么做。
如果先关闭的是服务端,那么客户端的子进程还在等待输入,直到你敲入一个字符。。。。
这个结果和我之前对于程序和键盘输入的理解不同,在以前,我以为直到敲击换行才会结束输入并将输入发送到进程,但是看起来似乎不是这样。
这个需要找人问一下了。客户端可以改成和服务端一样,相应信号。
#include<sys/types.h> #include<sys/socket.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> #include<stdio.h> #include <iostream> #include "signal.h" using namespace std; #define ERR_EXIT(m)\ do{\ perror(m);\ exit(EXIT_FAILURE);\ }while(0) void handle(int id) { printf("%d end\n",id); exit(1); } int main(void) { int sock; if((sock = socket(AF_INET,SOCK_STREAM,0)) < 0) ERR_EXIT("socket error"); struct sockaddr_in servaddr; memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if(connect(sock,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0) ERR_EXIT("connect error"); pid_t pid; pid = fork(); if(pid == -1) ERR_EXIT("fork error"); if(pid == 0)//此子进程用于发送数据 { signal(SIGUSR1,handle); char sendbuf[1024] = {0}; while(fgets(sendbuf,1024,stdin)!=NULL) { write(sock,sendbuf,strlen(sendbuf)); memset(sendbuf,0,sizeof(sendbuf)); } puts("client-child exit"); exit(EXIT_SUCCESS); } else//此进程用于接收数据 { char recvbuf[1024] = {0}; while(1) { int ret = read(sock,recvbuf,sizeof(recvbuf)); if(ret == -1) ERR_EXIT("read error"); else if (ret == 0) { printf("client close\n"); break; } fputs(recvbuf,stdout); memset(recvbuf,0,sizeof(recvbuf)); } kill(pid,SIGUSR1); sleep(2); exit(EXIT_SUCCESS); } }