一、服务器程序(server.c)
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/select.h> #include <netinet/in.h> #include <strings.h> #define SERV_PORT 9999 #define MAXLINE 4096 #define SA struct sockaddr int max(int, int); void proSession(FILE*, int, const struct sockaddr*); ssize_t writen(int, const void*, size_t); char *sock_ntop(const struct sockaddr*, socklen_t); int main(int argc, char *argv[]) { int listenfd, connfd; pid_t childpid; socklen_t clilen; struct sockaddr_in servaddr; struct sockaddr_in cliaddr; listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); bind(listenfd, (SA *)&servaddr, sizeof(servaddr)); /* 将套接字和套接字地址结构绑定 */ listen(listenfd, 1); /* 讲套接字转换为监听套接字 */ clilen = sizeof(cliaddr); if ( (connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) > 0) { proSession(stdin, connfd, (SA *)&cliaddr); /* 处理会话 */ } exit(1); } void proSession(FILE *fp, int sockfd, const struct sockaddr *addr) { int maxfdp1, stdineof; fd_set rset; char buf[MAXLINE]; int n; stdineof = 0; FD_ZERO(&rset); for ( ; ; ) { if (stdineof == 0) { FD_SET(fileno(fp), &rset); } FD_SET(sockfd, &rset); maxfdp1 = max(fileno(fp), sockfd) + 1; select(maxfdp1, &rset, NULL, NULL, NULL); if (FD_ISSET(sockfd, &rset)) { /* 套接字描述符可读 */ if ( (n = read(sockfd, buf, MAXLINE)) == 0) { if (stdineof == 1) { return; } else { exit(1); } } printf("%s\n", sock_ntop(addr, sizeof(addr))); write(fileno(stdout), buf, n); printf("\n"); } if (FD_ISSET(fileno(fp), &rset)) { /* 输入描述符可读 */ if ( (n = read(fileno(fp), buf, MAXLINE)) == 0) { stdineof = 1; shutdown(sockfd, SHUT_WR); /* 发送 FIN */ FD_CLR(fileno(fp), &rset); continue; } writen(sockfd, buf, n); } } } int max(int numberone, int numbertwo) { return ( (numberone >= numbertwo)?numberone:numbertwo); }
二、客户端程序(client.c)
#include <stdio.h> #include <stdlib.h> #include <strings.h> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #define SA struct sockaddr #define SERV_PORT 9999 #define MAXLINE 4096 int max(int, int); void proSession(FILE*, int, const struct sockaddr*); ssize_t writen(int, const void*, size_t); char *sock_ntop(const struct sockaddr*, socklen_t); int main(int argc, char *argv[]) { pid_t childpid; int sockfd; struct sockaddr_in servaddr; if (argc != 2) { printf("usage: %s <IPaddress>\n", argv[0]); exit(1); } sockfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); inet_pton(AF_INET, argv[1], &servaddr.sin_addr); if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) == 0) { proSession(stdin, sockfd, (SA *)&servaddr); /* 处理会话 */ } exit(1); } void proSession(FILE *fp, int sockfd, const struct sockaddr* addr) { int maxfdp1, stdineof; fd_set rset; char buf[MAXLINE]; int n; stdineof = 0; FD_ZERO(&rset); for ( ; ; ) { if (stdineof == 0) { FD_SET(fileno(fp), &rset); } FD_SET(sockfd, &rset); maxfdp1 = max(fileno(fp), sockfd) + 1; select(maxfdp1, &rset, NULL, NULL, NULL); if (FD_ISSET(sockfd, &rset)) { /* 套接字描述符就绪 */ if ( (n = read(sockfd, buf, MAXLINE)) == 0) { if (stdineof == 1) { return; } else { exit(1); } } printf("%s\n", sock_ntop(addr, sizeof(addr))); write(fileno(stdout), buf, n); printf("\n"); } if (FD_ISSET(fileno(fp), &rset)) { /* 输入描述符就绪 */ if ( (n = read(fileno(fp), buf, MAXLINE)) == 0) { stdineof = 1; shutdown(sockfd, SHUT_WR); /* 发送 FIN */ FD_CLR(fileno(fp), &rset); continue; } writen(sockfd, buf, n); } } } int max(int numberone, int numbertwo) { return ( (numberone >= numbertwo)?numberone:numbertwo); }
三、服务器程序和客户端程序都用到的程序
(1)sock_ntop.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <sys/un.h> #include <arpa/inet.h> #include <sys/socket.h> 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); }
(2)writen.c
#include <unistd.h> #include <errno.h> ssize_t writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwriten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nwriten = write(fd, ptr, nleft)) <= 0) { if (nwriten < 0 && errno) { nwriten = 0; /* call write() again */ } else { return (-1); /* error */ } } nleft -= nwriten; ptr += nwriten; } return (n - nwriten); }
四、Makefile文件
(1)服务器
target=server cc=gcc $(target):writen.o server.o sock_ntop.o $(cc) sock_ntop.o writen.o server.o -o $(target) sock_ntop.o:sock_ntop.c $(cc) -c sock_ntop.c -o sock_ntop.o writen.o:writen.c $(cc) -c writen.c -o writen.o server.o:server.c $(cc) -c server.c -o server.o clean: rm -rf *.o $(target)
(2)客户端
target=client cc=gcc $(target):writen.o client.o sock_ntop.o $(cc) writen.o client.o sock_ntop.o -o $(target) writen.o:writen.c $(cc) -c writen.c -o writen.o server.o:client.c $(cc) -c client.c -o client.o sock_ntop.o:sock_ntop.c $(cc) -c sock_ntop.c -o sock_ntop.o clean: rm -rf *.o $(target) ~