點對點聊天程式的實現
阿新 • • 發佈:2019-01-24
服務端
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0) //訊號處理函式,將自身退出 void handler(int sig) { printf("recv a dig=%d\n",sig); exit(EXIT_SUCCESS); } //只考慮一個服務端和一個客戶端,不考慮一個服務端和多個客戶端 int main(void) { int listenfd; if((listenfd=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0) /*if((listenfd=socket(PF_INET,SOCK_STREAM,0))<0) */ ERR_EXIT("socket"); 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); /*servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");*/ /*inet_aton("127.0.0.1,&servaddr.sin_addr");*/ int on=1; if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0) ERR_EXIT("setsockopt"); if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0) ERR_EXIT("bind"); if(listen(listenfd,SOMAXCONN)<0) ERR_EXIT("listen"); struct sockaddr_in peeraddr; socklen_t peerlen=sizeof(peeraddr); int conn; if((conn=accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen))<0) ERR_EXIT("accept"); printf("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"); //子程序用來發送資料 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)); } printf("child close\n"); 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"); } //說明對方關閉了 else if(ret==0) { printf("peer close\n"); break; } fputs(recvbuf,stdout); } printf("parent close\n"); //當父程序退出的時候,向子程序傳送一個訊號,子程序的程序號碼為pid //因為子程序還在等待從鍵盤輸入 kill(pid,SIGUSR1); exit(EXIT_SUCCESS); } return 0; }
客戶端
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.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 sock; if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0) /*if((listenfd=socket(PF_INET,SOCK_STREAM,0))<0) */ ERR_EXIT("socket"); 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"); /*inet_aton("127.0.0.1,&servaddr.sin_addr");*/ if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0) ERR_EXIT("connect"); pid_t pid; pid=fork(); if(pid==-1) { ERR_EXIT("fork"); } if(pid==0) { char recvbuf[1024]; while(1) { memset(recvbuf,0,sizeof(recvbuf)); int ret=read(sock,recvbuf,sizeof(recvbuf)); if(ret==-1) ERR_EXIT("read"); else if(ret==0) { printf("peer close\n"); break; } fputs(recvbuf,stdout); } close(sock); //通知父程序退出,因為父程序還在等待鍵盤輸入 kill(getppid(),SIGUSR1); } else { //接收子程序傳送過來的訊號 signal(SIGUSR1,handler); char sendbuf[1024]={0}; while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL) { write(sock,sendbuf,strlen(sendbuf)); memset(sendbuf,0,sizeof(sendbuf)); } close(sock); } return 0; }