思路:
点对点通信,其原理也比较简单,在前面回显服务器的基础上,我们分别在服务端和客户端都使用两个线程,一个线程负责发送数据包,一个线程负责接收数据包。
代码如下:
客户端:
/************************************************************************* > File Name: p2pcli.c > Author: ma6174 > Mail: ma6174@163.com > Created Time: Sun 05 Oct 2014 09:26:40 PM HKT ************************************************************************/ #include<stdio.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <netinet/in.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0) void handler(int sig) { printf("recv a sigal sig = %d ", sig); printf("parent exit "); exit(0); } int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr; if(argc != 2) { //printf("usage: p2pcli <IPaddress> "); //exit(0); ERR_EXIT("usage: p2pcli <IPaddress> "); } sockfd = socket(AF_INET, SOCK_STREAM, 0); memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = inet_addr(argv[1]); if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { ERR_EXIT("connect"); } pid_t pid; pid = fork(); if(pid == -1) { ERR_EXIT("fork"); } else if(pid == 0) { //child char recvbuf[1024] = {0}; while(1) { memset(recvbuf, 0, sizeof(recvbuf)); int ret = read(sockfd, recvbuf, sizeof(recvbuf)); if(ret == -1) { ERR_EXIT("read"); break; } else if(ret == 0) { printf("peer client close. "); break; } else { fputs(recvbuf, stdout); } } printf("child thread exit "); kill(getppid(), SIGUSR1); exit(EXIT_SUCCESS); } else { signal(SIGUSR1, handler); char sendbuf[1024] = {0}; while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL) { //send to server. write(sockfd, sendbuf, strlen(sendbuf)); memset(sendbuf, 0, sizeof(sendbuf)); } exit(EXIT_SUCCESS); } //communication return 0; }
服务端:
/************************************************************************* > File Name: p2psrv.c > Author: ma6174 > Mail: ma6174@163.com > Created Time: Sun 05 Oct 2014 08:27:06 PM HKT ************************************************************************/ #include<stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <string.h> #include <arpa/inet.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0) /** *child thread signal exit function **/ void handler(int sig) { printf("recv a signal sig=%d ", sig); printf("child exit "); exit(EXIT_SUCCESS); } int main() { int listenfd; if( (listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 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); //reuse address int on = 1; if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) { 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 connfd; if( (connfd = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0 ) { ERR_EXIT("accept"); } printf("ip=%s, port=%d ", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port)); pid_t pid; pid = fork(); if(pid == -1) { ERR_EXIT("fork"); } else if(pid == 0) { //child signal(SIGUSR1, handler); char sendbuf[1024]; memset(sendbuf, 0, sizeof(sendbuf)); while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL) { write(connfd, 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(connfd, recvbuf, sizeof(recvbuf)); if(ret == -1) { ERR_EXIT("read"); } else if(ret == 0) { printf("peer client close. "); break; } else { fputs(recvbuf, stdout); } } printf("parent exit "); kill(pid, SIGUSR1); exit(EXIT_SUCCESS); } close(connfd); close(listenfd); return 0; }