TCP编程之二
二 文件传输模型
util.c
1 #include <apue.h> 2 3 /** 4 * return value:ret 5 * ret<0 @error 6 * ret ==0 @success 7 * ret<len && ret>0 @socket is closed by peer 8 */ 9 int readn(int fd,void *buf,size_t len) 10 { 11 int total = 0,n; 12 while(total<len) 13 { 14 again: 15 if((n = read(fd,buf+total,len-total))<0) 16 { 17 if(errno==EINTR) 18 goto again; 19 return -1; 20 } 21 else if(n==0) 22 break; 23 total += n; 24 } 25 return total; 26 } 27 28 /** 29 * return value:ret 30 * ret<0 @error 31 * ret>=0 @success 32 */ 33 int writen(int fd,const void *buf,size_t len) 34 { 35 int total = 0,n; 36 while(total<len) 37 { 38 again: 39 if((n = write(fd,buf+total,len-total))<0) 40 { 41 if(errno==EINTR) 42 goto again; 43 return -1; 44 } 45 total += n; 46 } 47 return 0; 48 }
server.c
1 #include <apue.h> 2 #include "common.h" 3 #include "util.h" 4 5 #define PORT 8080 6 #define IP "192.168.5.99" 7 #define BACKLOG 10 8 9 #define FILENAME "passwd" 10 11 void *routine(void *arg); 12 void do_business(); 13 14 int main(int argc, char **argv) 15 { 16 int sockfd; 17 //1.创建socket 18 if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) 19 ERR("Socket failed"); 20 21 #if 0 22 struct sockaddr_in { 23 sa_family_t sin_family; 24 in_port_t sin_port; 25 struct in_addr sin_addr; 26 unsigned char sin_zero[8]; 27 }; 28 #endif 29 //2.给socket绑定地址 30 struct sockaddr_in ipv4, peer; 31 ipv4.sin_family = AF_INET; 32 ipv4.sin_port = htons(PORT); //NBO 33 inet_pton(AF_INET, IP, &ipv4.sin_addr); //NBO 34 memset(ipv4.sin_zero, 0, sizeof(ipv4.sin_zero)); 35 if (bind(sockfd, (struct sockaddr *) &ipv4, sizeof(ipv4)) < 0) 36 ERR("bind failed"); 37 38 //3.监听 39 if (listen(sockfd, BACKLOG) < 0) 40 ERR("listen failed"); 41 42 //4.接收连接 43 socklen_t len = sizeof(peer); //value-result argument 44 int connfd; 45 for (;;) { 46 if ((connfd = accept(sockfd, (struct sockaddr *) &peer, &len)) < 0) 47 ERR("accept failed"); 48 49 unsigned short peerport = ntohs(peer.sin_port); 50 char ipstr[] = "ddd.ddd.ddd.ddd"; 51 inet_ntop(AF_INET, &peer.sin_addr, ipstr, sizeof(ipstr)); 52 53 //5.通信 54 char banner[255]; 55 sprintf(banner, "[%s:%d] welcome to echoserver!", ipstr, 56 peerport); 57 printf("Accept a new Connection: %s,%d\n",ipstr,peerport); 58 if(write(connfd, banner, strlen(banner)) < strlen(banner)) 59 ERR("write failed"); 60 61 #ifdef MODEL_THREAD 62 pthread_t tid; 63 if(pthread_create(&tid,NULL,routine,(void*)connfd)) 64 ERR("create thread failed"); 65 #elif MODEL_FORK 66 pid_t pid; 67 if((pid = fork())<0) 68 ERR("fork failed"); 69 else if(pid==0) 70 { 71 close(sockfd); //1.关闭无用描述符 72 do_business(connfd); 73 exit(0); //2.显式指定退出 74 } 75 close(connfd); 76 #endif 77 } 78 //7.关闭服务器 79 close(sockfd); 80 return 0; 81 } 82 83 void do_business() 84 { 85 sleep(20); 86 } 87 88 void *routine(void *arg) 89 { 90 int n,fd,connfd = (int)arg; 91 92 struct stat st; 93 if(stat(FILENAME,&st)<0) 94 ERR("stat failed"); 95 size_t filesize = st.st_size; 96 97 //1.send filename 98 if(writen(connfd,FILENAME,LEN_FILENAME)<0) 99 ERR("write fialed"); 100 //2.send filesize 101 int filesize_nbo = htonl(filesize); 102 if(writen(connfd,&filesize_nbo,LEN_FILESIZE)<0) 103 ERR("write failed"); 104 //3.send filecontent <loop> 105 if((fd = open(FILENAME,O_RDONLY))<0) 106 ERR("open failed"); 107 char buf[LEN_BUF]; 108 while(1) 109 { 110 if((n = read(fd,buf,LEN_BUF))<0) 111 ERR("read failed"); 112 else if(n==0) //EOF 113 break; 114 if(writen(connfd,buf,n)<0) 115 ERR("write failed"); 116 } 117 close(fd); 118 close(connfd); 119 120 return NULL; 121 }
client.c
1 #include <apue.h> 2 #include "common.h" 3 #include "util.h" 4 5 void do_business(int sockfd); 6 7 int main(int argc,char **argv) 8 { 9 //1.判断命令行 10 if(argc!=3) 11 { 12 printf("Usage: %s <host> <port>\n",argv[0]); 13 exit(0); 14 } 15 char *ipstr = argv[1]; 16 unsigned short port = strtol(argv[2],NULL,10); 17 18 //2.socket 19 int sockfd; 20 if((sockfd = socket(PF_INET,SOCK_STREAM,0))<0) 21 ERR("socket failed"); 22 23 //3.connect 24 struct sockaddr_in peer; 25 CLEAR(peer); 26 peer.sin_family = AF_INET; 27 peer.sin_port = htons(port); 28 inet_pton(AF_INET,ipstr,&peer.sin_addr); 29 if(connect(sockfd,(struct sockaddr*)&peer,sizeof(peer))<0) 30 ERR("connect failed"); 31 32 //4.交互 33 char banner[255]; 34 int n; 35 if((n = read(sockfd,banner,sizeof(banner)))<0) 36 ERR("read failed"); 37 else if(n==0) 38 goto end; 39 banner[n] = 0; 40 printf("%s\n",banner); 41 42 do_business(sockfd); 43 44 //5.关闭 45 end: 46 close(sockfd); 47 48 return 0; 49 } 50 51 void do_business(int sockfd) 52 { 53 int n; 54 char filename[LEN_FILENAME]; 55 //1.read filename 56 if((n=readn(sockfd,filename,LEN_FILENAME))<0) 57 ERR("read failed"); 58 else if(n<LEN_FILENAME) 59 { 60 fprintf(stderr,"Connection is closed by peer!\n"); 61 return; 62 } 63 64 //2.read filesize 65 size_t filesize_nbo,filesize; 66 if((n=readn(sockfd,&filesize_nbo,LEN_FILESIZE))<0) 67 ERR("read failed"); 68 else if(n<LEN_FILESIZE) 69 { 70 fprintf(stderr,"Connection is closed by peer!\n"); 71 return; 72 } 73 filesize = ntohl(filesize_nbo); 74 75 //3.read filecontent 76 int fd,total = 0; 77 if((fd = open(filename,O_WRONLY|O_CREAT,0644))<0) 78 ERR("Open file failed"); 79 char buf[LEN_BUF]; 80 while(total<filesize) 81 { 82 if((n=read(sockfd,buf,LEN_BUF))<0) 83 ERR("read failed"); 84 else if(n==0) 85 { 86 fprintf(stderr,"Connection is closed by peer!\n"); 87 return; 88 } 89 if(writen(fd,buf,n)<0) 90 ERR("write failed"); 91 total += n; 92 } 93 }