一、技术简介
(1)服务端打开两个端口9999和6666监听外来连接;
(2)服务端的子进程通过端口9999监听外来消息,通过端口6666发送消息;
(3)客户端的子进程处理外来消息,父进程发送消息
二、服务器程序
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/un.h> #define SERV_PORT1 9999 #define SERV_PORT2 6666 #define MAXLINE 4096 #define SA struct sockaddr void send_msg(int); void listen_msg(int, const struct sockaddr*); char *sock_ntop(const struct sockaddr*, socklen_t); int main(int argc, char *argv[]) { int listenfd1, connfd1; int listenfd2, connfd2; pid_t childpid; socklen_t clilen1, clilen2; struct sockaddr_in servaddr1, servaddr2; struct sockaddr_in cliaddr1, cliaddr2; listenfd1 = socket(AF_INET, SOCK_STREAM, 0); listenfd2 = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr1, sizeof(servaddr1)); servaddr1.sin_family = AF_INET; servaddr1.sin_addr.s_addr = htonl(INADDR_ANY); servaddr1.sin_port = htons(SERV_PORT1); bzero(&servaddr2, sizeof(servaddr2)); servaddr2.sin_family = AF_INET; servaddr2.sin_addr.s_addr = htonl(INADDR_ANY); servaddr2.sin_port = htons(SERV_PORT2); bind(listenfd1, (SA *)&servaddr1, sizeof(servaddr1)); bind(listenfd2, (SA *)&servaddr2, sizeof(servaddr2)); listen(listenfd1, 1); listen(listenfd2, 1); clilen1 = sizeof(cliaddr1); clilen2 = sizeof(cliaddr2); connfd1 = accept(listenfd1, (SA *)&cliaddr1, &clilen1); connfd2 = accept(listenfd2, (SA *)&cliaddr2, &clilen2); if (connfd1 && connfd2) { if ( (childpid = fork()) == 0) { close(listenfd2); close(connfd2); close(listenfd1); listen_msg(connfd1, (SA *)&cliaddr1); close(connfd1); exit(0); } close(listenfd1); close(connfd1); close(listenfd2); send_msg(connfd2); close(connfd2); } exit(0); } void listen_msg(int sockfd, const struct sockaddr *addr) { ssize_t n; char buf[MAXLINE]; while ( (n = read(sockfd, buf, MAXLINE)) > 0) { printf("[%s]: ", sock_ntop(addr, sizeof(addr))); fputs(buf, stdout); bzero(buf, sizeof(buf)); } } void send_msg(int sockfd) { char buf[MAXLINE]; while (fgets(buf, MAXLINE, stdin) != NULL) { write(sockfd, buf, sizeof(buf)); } } char *sock_ntop(const struct sockaddr *sa, socklen_t salen) { char portstr[8]; static char str[128]; switch (sa->sa_family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *) sa; if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) { return(NULL); } if (ntohs(sin->sin_port) != 0) { snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port)); strcat(str, portstr); } return(str); } case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; str[0] = '['; if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1, sizeof(str) - 1) == NULL) { return(NULL); } if (ntohs(sin6->sin6_port) != 0) { snprintf(portstr, sizeof(portstr), "]:%d", ntohs(sin6->sin6_port)); strcat(str, portstr); return(str); } return (str + 1); } case AF_UNIX: { struct sockaddr_un *unp = (struct sockaddr_un *) sa; if (unp->sun_path[0] == 0) { strcpy(str, "(no pathname bound)"); } else { snprintf(str, sizeof(str), "%s", unp->sun_path); } return(str); } default: { snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family, salen); return(str); } } return (NULL); }
三、客户端程序
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/un.h> #define SA struct sockaddr #define SERV_PORT1 9999 #define SERV_PORT2 6666 #define MAXLINE 4096 void send_msg(int); void listen_msg(int, const struct sockaddr*); char *sock_ntop(const struct sockaddr*, socklen_t); int main(int argc, char *argv[]) { pid_t childpid; int sockfd1,sockfd2; int connstatus1, connstatus2; struct sockaddr_in servaddr1, servaddr2; if (argc != 2) { printf("usage: %s <IPaddress>\n", argv[0]); exit(0); } sockfd1 = socket(AF_INET, SOCK_STREAM, 0); sockfd2 = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr1, sizeof(servaddr1)); servaddr1.sin_family = AF_INET; servaddr1.sin_port = htons(SERV_PORT1); inet_pton(AF_INET, argv[1], &servaddr1.sin_addr); bzero(&servaddr2, sizeof(servaddr2)); servaddr2.sin_family = AF_INET; servaddr2.sin_port = htons(SERV_PORT2); inet_pton(AF_INET, argv[1], &servaddr2.sin_addr); connstatus1 = connect(sockfd1, (SA *)&servaddr1, sizeof(servaddr1)); connstatus2 = connect(sockfd2, (SA *)&servaddr2, sizeof(servaddr2)); if (connstatus1 == 0 && connstatus2 == 0) { if ( (childpid = fork()) == 0) { close(sockfd1); listen_msg(sockfd2, (SA *)&servaddr2); close(sockfd2); exit(0); } close(sockfd2); send_msg(sockfd1); close(sockfd1); } else { printf("connect failed!\n"); } exit(0); } void listen_msg(int sockfd, const struct sockaddr *addr) { ssize_t n; char buf[MAXLINE]; while ( (n = read(sockfd, buf, MAXLINE)) > 0) { printf("[%s]: ", sock_ntop(addr, sizeof(addr))); fputs(buf, stdout); bzero(buf, sizeof(buf)); } } void send_msg(int sockfd) { char buf[MAXLINE]; while (fgets(buf, MAXLINE, stdin) != NULL) { write(sockfd, buf, sizeof(buf)); } } char *sock_ntop(const struct sockaddr *sa, socklen_t salen) { char portstr[8]; static char str[128]; switch (sa->sa_family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *) sa; if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) { return(NULL); } if (ntohs(sin->sin_port) != 0) { snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port)); strcat(str, portstr); } return(str); } case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; str[0] = '['; if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1, sizeof(str) - 1) == NULL) { return(NULL); } if (ntohs(sin6->sin6_port) != 0) { snprintf(portstr, sizeof(portstr), "]:%d", ntohs(sin6->sin6_port)); strcat(str, portstr); return(str); } return (str + 1); } case AF_UNIX: { struct sockaddr_un *unp = (struct sockaddr_un *) sa; if (unp->sun_path[0] == 0) { strcpy(str, "(no pathname bound)"); } else { snprintf(str, sizeof(str), "%s", unp->sun_path); } return(str); } default: { snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family, salen); return(str); } } return (NULL); }