学习 UNIX网络编程卷1:套接字 笔记1-实现一个简单的回射客户服务器程序
一:客户端程序
1、头文件:unp.h
1 #ifndef _unp_h 2 #define _unp_h 3 #include <sys/types.h> /* basic system data types */ 4 #include <sys/socket.h> /* basic socket definitions */ 5 #include <sys/time.h> /* timeval{} for select() */ 6 #include <time.h> /* timespec{} for pselect() */ 7 #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ 8 #include <arpa/inet.h> /* inet(3) functions */ 9 #include <errno.h> 10 #include <fcntl.h> /* for nonblocking */ 11 #include <netdb.h> 12 #include <signal.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/stat.h> /* for S_xxx file mode constants */ 17 #include <sys/uio.h> /* for iovec{} and readv/writev */ 18 #include <unistd.h> 19 #include <sys/wait.h> 20 #include <sys/un.h> /* for Unix domain sockets */ 21 #define MAXLINE 4096 22 #define LISTENQ 5 23 #define SERV_PORT 9877 24 int Socket(int sockfd, int type, int protocol); 25 void Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen); 26 void Listen(int sockfd,int backlog); 27 void Connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); 28 int Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); 29 void Write(int fd,void *buf,size_t count); 30 void Close(int sockfd); 31 void err_sys(char *err_str); 32 int Fork(); 33 void str_echo(int sockfd); 34 ssize_t writen(int fd, char *buf, size_t n); 35 ssize_t Writen(int fd, char *buf, size_t n); 36 void str_cli(FILE *fp, int sockfd); 37 ssize_t readline(int fd, void *vptr, size_t maxlen); 38 ssize_t Readline(int fd, void *vptr, size_t maxlen); 39 #endif
2、客户端主程序:clien.c
1 #include "unp.h" 2 3 int main(int argc,char **argv) 4 { 5 char ip_addr[20]; 6 int sockfd; 7 struct sockaddr_in servaddr; 8 /**add for ipaddress **/ 9 /* 10 if (argc != 2) 11 { 12 err_sys("usage:clien <IPaddress>"); 13 return -1; 14 } 15 */ 16 17 bzero(&servaddr, sizeof(servaddr)); 18 bzero(ip_addr,sizeof(ip_addr)); 19 /**add for ipaddress**/ 20 //strcpy(ip_addr,argv[1]); 21 sockfd = Socket(AF_INET, SOCK_STREAM, 0); 22 23 servaddr.sin_family = AF_INET; 24 servaddr.sin_port = htons(SERV_PORT); 25 servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 26 //servaddr.sin_addr.s_addr = inet_addr(ip_addr); 27 Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); 28 29 str_cli(stdin,sockfd); 30 31 return 0; 32 33 }
3、客户端包裹函数:pack.c
1 #include "unp.h" 2 3 void err_sys(char *err_str) 4 { 5 perror(err_str); 6 } 7 8 int Socket(int sockfd, int type, int protocol) 9 { 10 int n=0; 11 if ((n=socket(sockfd,type,protocol))<0) 12 { 13 err_sys("socket error"); 14 } 15 return n; 16 } 17 18 void Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen) 19 { 20 int n=0; 21 if ((n = bind(sockfd,myaddr,addrlen))<0) 22 { 23 err_sys("bind error"); 24 } 25 } 26 27 void Listen(int sockfd,int backlog) 28 { 29 char *ptr=NULL; 30 if ((ptr=getenv("LISTENQ"))!=NULL) 31 { 32 backlog=atoi(ptr); 33 } 34 if (listen(sockfd,backlog)<0) 35 { 36 err_sys("listen error"); 37 } 38 } 39 40 void Connect(int sockfd,const struct sockaddr *servaddr, socklen_t addrlen) 41 { 42 if(connect(sockfd,servaddr,addrlen)<0) 43 { 44 err_sys("connect error"); 45 } 46 else 47 { 48 printf("connect success!\n"); 49 } 50 } 51 52 int Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen) 53 { 54 int n; 55 again: 56 if ((n=accept(sockfd,cliaddr,addrlen))<0) 57 { 58 #ifndef EPROTO 59 if(errno == EPROTO || errno == ECONNABORTED) 60 #else 61 if(errno == ECONNABORTED) 62 #endif 63 { 64 goto again; 65 } 66 else 67 { 68 err_sys("accept error"); 69 } 70 } 71 return n; 72 } 73 74 ssize_t Writen(int fd,char *buf, size_t n) 75 { 76 ssize_t ret; 77 ret = writen(fd,buf,n); 78 if (ret < 0) 79 { 80 err_sys("writen error"); 81 return -1; 82 } 83 return ret; 84 } 85 86 ssize_t Readline(int fd, void *vptr, size_t maxlen) 87 { 88 ssize_t n; 89 n=readline(fd,vptr,maxlen); 90 if (n<0) 91 { 92 err_sys("readline error"); 93 return -1; 94 } 95 return n; 96 }
4、客户端功能行函数:func.c
1 #include "unp.h" 2 ssize_t writen(int fd, char *buf, size_t n) 3 { 4 size_t nleft; 5 ssize_t nwritten; 6 char *ptr; 7 ptr = buf; 8 nleft = n ; 9 while(nleft > 0) 10 { 11 nwritten = write(fd, ptr, nleft); 12 if (nwritten < 0 && errno == EINTR) 13 { 14 nwritten = 0; 15 } 16 else if (nwritten < 0) 17 { 18 err_sys("write error"); 19 return -1; 20 } 21 22 nleft -= nwritten; 23 ptr += nwritten; 24 } 25 return n; 26 } 27 28 void str_echo(int sockfd) 29 { 30 ssize_t n; 31 char buf[MAXLINE]; 32 again: 33 while ((n = read(sockfd, buf, MAXLINE))>0) 34 Writen(sockfd, buf, n); 35 if (n < 0 && errno == EINTR) 36 { 37 goto again; 38 } 39 else if (n < 0) 40 { 41 err_sys("str_echo error"); 42 } 43 } 44 ssize_t readline(int fd, void *vptr, size_t maxlen) 45 { 46 ssize_t n,rc; 47 char c,*ptr; 48 ptr = vptr; 49 for (n = 1; n < maxlen; n++) 50 { 51 again: 52 if ((rc = read(fd, &c, 1)) == 1) 53 { 54 *ptr++ = c; 55 if (c == '\n') 56 { 57 break; 58 } 59 } 60 else if (rc == 0) 61 { 62 *ptr = 0; 63 return (n-1); 64 } 65 else 66 { 67 if (errno == EINTR) 68 { 69 goto again; 70 } 71 return -1; 72 } 73 } 74 *ptr = 0; 75 return n; 76 } 77 78 void str_cli(FILE *fp, int sockfd) 79 { 80 char sendline[MAXLINE],recvline[MAXLINE]; 81 bzero(sendline,sizeof(sendline)); 82 bzero(recvline,sizeof(recvline)); 83 84 while(fgets(sendline,MAXLINE,fp) != NULL) 85 { 86 Writen(sockfd,sendline,strlen(sendline)); 87 if (Readline(sockfd, recvline, MAXLINE) == 0) 88 { 89 err_sys("str_cli Readline error"); 90 } 91 fputs(recvline, stdout); 92 } 93 }
5、客户端Makefile
1 clien:clien.o pack.o func.o 2 gcc clien.o pack.o func.o -o clien 3 clien.o:clien.c unp.h 4 gcc -c clien.c -o clien.o 5 pack.o:pack.c unp.h 6 gcc -c pack.c -o pack.o 7 func.o:func.c unp.h 8 gcc -c func.c -o func.o 9 .PHONY:clean 10 clean: 11 rm -f *.o
二:服务器程序
1、头文件:unp.h
1 #ifndef _unp_h 2 #define _unp_h 3 #include <sys/types.h> /* basic system data types */ 4 #include <sys/socket.h> /* basic socket definitions */ 5 #include <sys/time.h> /* timeval{} for select() */ 6 #include <time.h> /* timespec{} for pselect() */ 7 #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ 8 #include <arpa/inet.h> /* inet(3) functions */ 9 #include <errno.h> 10 #include <fcntl.h> /* for nonblocking */ 11 #include <netdb.h> 12 #include <signal.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/stat.h> /* for S_xxx file mode constants */ 17 #include <sys/uio.h> /* for iovec{} and readv/writev */ 18 #include <unistd.h> 19 #include <sys/wait.h> 20 #include <sys/un.h> /* for Unix domain sockets */ 21 #define MAXLINE 4096 22 #define LISTENQ 5 23 #define SERV_PORT 9877 24 typedef void (*sighandler_t)(int); 25 sighandler_t Signal(int signum, sighandler_t handler); 26 int Socket(int sockfd, int type, int protocol); 27 void Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen); 28 void Listen(int sockfd,int backlog); 29 void Connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); 30 int Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); 31 void Write(int fd,void *buf,size_t count); 32 void Close(int sockfd); 33 void err_sys(char *err_str); 34 int Fork(); 35 void str_echo(int sockfd); 36 ssize_t writen(int fd, char *buf, size_t n); 37 ssize_t Writen(int fd, char *buf, size_t n); 38 void sig_chlid(int signo); 39 #endif
2、服务器主程序:serv.c
1 #include "unp.h" 2 void sig_chld(int ); 3 4 int main(int argc, char const *argv[]) 5 { 6 int listenfd,connfd; 7 pid_t childpid; 8 socklen_t clilen; 9 struct sockaddr_in cliaddr,servaddr; 10 listenfd = Socket(AF_INET, SOCK_STREAM, 0);//监听套接字创建 11 bzero(&servaddr, sizeof(servaddr)); 12 servaddr.sin_family = AF_INET;//服务器地址族 13 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//服务器地址赋值,一般服务器地址不指定 14 servaddr.sin_port = htons(SERV_PORT);//服务器端口赋值 15 Bind(listenfd,(struct sockaddr*)&servaddr, sizeof(servaddr));//绑定监听套接字与服务器的端口 16 Listen(listenfd, LISTENQ); //监听 17 Signal(SIGCHLD, sig_chld); //回收僵死子进程 18 while(1) 19 { 20 clilen = sizeof(cliaddr); 21 connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);//accept创建已连接套接字connfd 22 if (connfd<0) { 23 if(errno == EINTR)//处理系统中断 24 { 25 continue; 26 } 27 else 28 { 29 err_sys("accept error"); 30 } 31 } 32 if ((childpid = Fork()) == 0)//创建子进程 33 { 34 Close(listenfd);//子进程关闭监听套接字 35 str_echo(connfd);//调用回射函数 36 exit(0); 37 } 38 else//父进程 39 { 40 Close(connfd);//父进程关闭已连接套接字 41 } 42 43 } 44 return 0; 45 }
3、包裹函数:pack.c
1 #include "unp.h" 2 3 void err_sys(char *err_str) 4 { 5 perror(err_str); 6 } 7 8 int Socket(int sockfd, int type, int protocol) 9 { 10 int n=0; 11 if ((n=socket(sockfd,type,protocol))<0) 12 { 13 err_sys("socket error"); 14 } 15 printf("socket success!sockfd=%d\n",n); 16 return n; 17 } 18 19 void Bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen) 20 { 21 int n=0; 22 if ((n = bind(sockfd,myaddr,addrlen))<0) 23 { 24 err_sys("bind error"); 25 } 26 printf("bind success\n"); 27 } 28 29 void Listen(int sockfd,int backlog) 30 { 31 char *ptr=NULL; 32 if ((ptr=getenv("LISTENQ"))!=NULL) 33 { 34 backlog=atoi(ptr); 35 } 36 if (listen(sockfd,backlog)<0) 37 { 38 err_sys("listen error"); 39 } 40 printf("listen success\n"); 41 } 42 43 void Connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen) 44 { 45 if(connect(sockfd,servaddr,addrlen)<0) 46 { 47 err_sys("connect error"); 48 } 49 printf("connect success!\n"); 50 } 51 52 int Accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen) 53 { 54 int n; 55 again: 56 if ((n=accept(sockfd,cliaddr,addrlen))<0) 57 { 58 #ifndef EPROTO 59 if(errno == EPROTO || errno == ECONNABORTED) 60 #else 61 if(errno == ECONNABORTED) 62 #endif 63 { 64 goto again; 65 } 66 else 67 { 68 err_sys("accept error"); 69 } 70 } 71 return n; 72 } 73 74 /* 75 char* Inet_ntop(int family, const void *addrptr,char *strptr,size_t len) 76 { 77 char buff[1024+1]; 78 bzero(buff,sizeof(buff)); 79 if(inet_ntop(family,addrptr,strptr,len)==NULL) 80 { 81 err_sys("inet_error"); 82 } 83 strcpy(buff,strptr); 84 return buff; 85 } 86 */ 87 void Write(int fd,void *buf,size_t count) 88 { 89 ssize_t n; 90 n=write(fd,buf,count); 91 if(n!=count) 92 { 93 err_sys("write error"); 94 } 95 96 } 97 void Close(int sockfd) 98 { 99 if(close(sockfd)==-1) 100 { 101 err_sys("close error"); 102 } 103 } 104 105 int Fork() 106 { 107 pid_t pid; 108 if ((pid = fork()) < 0) 109 { 110 err_sys("fork error"); 111 } 112 else 113 return pid; 114 } 115 116 ssize_t Writen(int fd,char *buf, size_t n) 117 { 118 ssize_t ret; 119 ret = writen(fd,buf,n); 120 if (ret < 0) 121 { 122 err_sys("writen error"); 123 return -1; 124 } 125 return ret; 126 } 127 128 sighandler_t Signal(int signum, sighandler_t handler) 129 { 130 if (signal(signum, handler)==SIG_ERR) 131 { 132 err_sys("signal error"); 133 exit(-1); 134 } 135 136 }
4、功能性函数:func.c
1 #include "unp.h" 2 3 ssize_t writen(int fd, char *buf, size_t n) 4 { 5 size_t nleft; 6 ssize_t nwritten; 7 char *ptr; 8 ptr = buf; 9 nleft = n ; 10 while(nleft > 0) 11 { 12 nwritten = write(fd, ptr, nleft); 13 if (nwritten < 0 && errno == EINTR) 14 { 15 nwritten = 0; 16 } 17 else if (nwritten < 0) 18 { 19 err_sys("write error"); 20 return -1; 21 } 22 23 nleft -= nwritten; 24 ptr += nwritten; 25 } 26 return n; 27 } 28 29 void str_echo(int sockfd) 30 { 31 ssize_t n; 32 char buf[MAXLINE]; 33 again: 34 while ((n = read(sockfd, buf, MAXLINE))>0) 35 Writen(sockfd, buf, n); 36 if (n < 0 && errno == EINTR) 37 { 38 goto again; 39 } 40 else if (n < 0) 41 { 42 err_sys("str_echo error"); 43 } 44 } 45 46 void sig_chld(int signum) 47 { 48 pid_t pid; 49 int stat; 50 51 while(pid = waitpid(-1, &stat, WNOHANG) >0 ) 52 printf("chlid %d terminated!\n",pid); 53 return ; 54 }
5、服务器Makefile
1 serv:serv.o pack.o func.o 2 gcc serv.o pack.o func.o -o serv 3 serv.o:serv.c unp.h 4 gcc -c serv.c -o serv.o 5 pack.o:pack.c unp.h 6 gcc -c pack.c -o pack.o 7 func.o:func.c unp.h 8 gcc -c func.c -o func.o 9 .PHONY:clean 10 clean: 11 rm -f *.o