实现点对点通信,双方都能发送数据、接收数据,双方维护套接字。read对方数据和read键盘输入目前使用两个进程来实现。
服务器进程:
1 #include<unistd.h> 2 #include<sys/types.h> 3 #include<sys/socket.h> 4 #include<string.h> 5 #include<stdlib.h> 6 #include<stdio.h> 7 #include<errno.h> 8 #include<netinet/in.h> 9 #include<arpa/inet.h> 10 #include<signal.h> 11 #define ERR_EXIT(m) 12 do 13 { 14 perror(m); 15 exit(EXIT_FAILURE); 16 }while(0) 17 void handler(int sig) 18 { 19 printf("recv a sig=%d ",sig); 20 printf("ser child close"); 21 exit(EXIT_SUCCESS);//退出子进程 22 23 } 24 int main(void) 25 { 26 int listenfd; 27 if((listenfd=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0) 28 ERR_EXIT("socket error"); 29 //if((listenfd=socket(PF_INET,SOCK_STREAM,0))<0) 30 31 32 //本地协议地址赋给一个套接字 33 struct sockaddr_in servaddr; 34 memset(&servaddr,0,sizeof(servaddr)); 35 servaddr.sin_family=AF_INET; 36 servaddr.sin_port=htons(5188); 37 servaddr.sin_addr.s_addr=htonl(INADDR_ANY);//表示本机地址 38 //servaddr.sin_addr.s_addr=inet_addr("127.0.0.1"); 39 //inet_aton("127.0.0.1",&servaddr.sin_addr); 40 41 //开启地址重复使用,关闭服务器再打开不用等待TIME_WAIT 42 int on=1; 43 if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0) 44 ERR_EXIT("setsockopt error"); 45 //绑定本地套接字 46 if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0) 47 ERR_EXIT("bind error"); 48 if(listen(listenfd,SOMAXCONN)<0)//设置监听套接字(被动套接字) 49 ERR_EXIT("listen error"); 50 51 struct sockaddr_in peeraddr;//对方套接字地址 52 socklen_t peerlen=sizeof(peeraddr); 53 int conn;//已连接套接字(主动套接字) 54 if((conn=accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen))<0) 55 ERR_EXIT("accept error"); 56 printf("IP=%s,port=%d ",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port)); 57 pid_t pid; 58 pid=fork(); 59 if(pid==-1) 60 ERR_EXIT("fork"); 61 if(pid==0) 62 { 63 signal(SIGUSR1,handler); 64 //子进程获取键盘输入,发送数据 65 char sendbuf[1024]={0}; 66 while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL) 67 { 68 write(conn,sendbuf,strlen(sendbuf)); 69 memset(sendbuf,0,sizeof(sendbuf)); 70 } 71 //printf("child close "); 72 exit(EXIT_SUCCESS); 73 } 74 else 75 { 76 //父进程获取对方数据 77 char recvbuf[1024]; 78 while(1) 79 { 80 memset(recvbuf,0,sizeof(recvbuf)); 81 int ret=read(conn,recvbuf,sizeof(recvbuf)); 82 if(ret==-1) 83 ERR_EXIT("read"); 84 else if(ret==0) 85 { 86 printf("peer closed"); 87 break; 88 } 89 fputs(recvbuf,stdout); 90 } 91 //printf("ser father close"); 92 kill(pid,SIGUSR1);//通知子进程 93 exit(EXIT_SUCCESS); 94 } 95 return 0; 96 }
客户端程序代码:
1 #include<unistd.h> 2 #include<sys/types.h> 3 #include<sys/socket.h> 4 #include<string.h> 5 #include<stdlib.h> 6 #include<stdio.h> 7 #include<errno.h> 8 #include<netinet/in.h> 9 #include<arpa/inet.h> 10 #include<signal.h> 11 #define ERR_EXIT(m) 12 do 13 { 14 perror(m); 15 exit(EXIT_FAILURE); 16 }while(0) 17 void handler(int sig) 18 { 19 printf("recv a sig=%d ",sig); 20 exit(EXIT_SUCCESS); 21 } 22 int main(void) 23 { 24 int sock;//客户端创建套接字 25 if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0) 26 ERR_EXIT("socket error"); 27 28 struct sockaddr_in servaddr;//本地协议地址赋给一个套接字 29 memset(&servaddr,0,sizeof(servaddr)); 30 servaddr.sin_family=AF_INET; 31 servaddr.sin_port=htons(5188); 32 33 servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");//服务器段地址 34 //inet_aton("127.0.0.1",&servaddr.sin_addr); 35 36 if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0) 37 ERR_EXIT("connect"); 38 39 40 pid_t pid; 41 pid=fork(); 42 if(pid==-1) 43 ERR_EXIT("fork"); 44 if(pid==0) 45 { 46 char recvbuf[1024]; 47 //子进程接收对方数据,服务器端也能发送数据。 48 while(1) 49 { 50 memset(recvbuf,0,sizeof(recvbuf)); 51 int ret=read(sock,recvbuf,sizeof(recvbuf)); 52 if(ret==-1) 53 ERR_EXIT("read"); 54 else if(ret==0) 55 { 56 printf("peer closed "); 57 break; 58 } 59 fputs(recvbuf,stdout); 60 } 61 close(sock); 62 //break跳出循环的话,说明服务端关闭了.那么给父进程发送信号通知父进程 63 //父进程是给对方发送数据的,对方关闭了,那么父进程收到信号后,退出进程,不再发送数据。 64 kill(getppid(),SIGUSR1); 65 exit(EXIT_SUCCESS); 66 } 67 else 68 { 69 signal(SIGUSR1,handler);//如果没有这个,父进程不会退出 70 //父进程发送数据 71 char sendbuf[1024]={0}; 72 while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)//默认有换行符 73 { 74 write(sock,sendbuf,strlen(sendbuf)); 75 memset(sendbuf,0,sizeof(sendbuf)); 76 } 77 close(sock); 78 printf("cli father close "); 79 exit(EXIT_SUCCESS); 80 } 81 return 0; 82 }