一、针对ECHO服务的TCP客户软件的实现
1.网络拓扑结构:
2.源码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <string.h> 5 #include <stdarg.h> 6 #include <sys/types.h> 7 #include <sys/socket.h> 8 #include <netinet/in.h> 9 #include <arpa/inet.h> 10 #include <netdb.h> 11 #include <errno.h> 12 13 #define LINELEN 128 14 extern int errno; 15 16 int TCPecho(const char *host, const char *service); 17 int errexit(const char *format,...); 18 int connectsock(const char *host, const char *service, const char *transport ); 19 int connectTCP(const char *host, const char *service); 20 21 int main(int argc, char *argv[]){ 22 char *host= "localhost"; 23 char *service= "echo"; 24 switch(argc){ 25 case 1: 26 host = "localhost"; 27 break; 28 case 3: 29 service = argv[2]; 30 case 2: 31 host=argv[1]; 32 break; 33 default: 34 fprintf(stderr,"usage:TCPecho[host[port]]\n"); 35 exit(1); 36 } 37 TCPecho(host,service); 38 exit(0); 39 } 40 int TCPecho(const char *host,const char *service){ 41 char buf[LINELEN+1]; 42 int s,n; 43 int outchars, inchars; 44 s=connectTCP(host, service); 45 while(fgets(buf,sizeof(buf),stdin)){ 46 buf[LINELEN]='\0'; 47 outchars=strlen(buf); 48 (void)write(s,buf,outchars); 49 for(inchars=0;inchars<outchars;inchars+=n){ 50 n=read(s,&buf[inchars],outchars-inchars); 51 if(n<0) 52 errexit("socker read failed: %s\n",strerror(errno)); 53 } 54 fputs(buf,stdout); 55 } 56 } 57 int errexit(const char *format,...){ 58 va_list arg; 59 va_start(arg, format); 60 vfprintf(stderr,format,arg); 61 va_end(arg); 62 exit(1); 63 } 64 int connectsock(const char *host, const char *service, const char *transport ) 65 /* 66 * Arguments: 67 * host - name of host to which connection is desired 68 * service - service associated with the desired port 69 * transport - name of transport protocol to use ("tcp" or "udp") 70 */ 71 { 72 struct hostent *phe; /* pointer to host information entry */ 73 struct servent *pse; /* pointer to service information entry */ 74 struct protoent *ppe; /* pointer to protocol information entry*/ 75 struct sockaddr_in sin; /* an Internet endpoint address */ 76 int s, type; /* socket descriptor and socket type */ 77 78 79 memset(&sin, 0, sizeof(sin)); 80 sin.sin_family = AF_INET; 81 82 /* Map service name to port number */ 83 if ( pse = getservbyname(service, transport) ) 84 sin.sin_port = pse->s_port; 85 else if ((sin.sin_port=htons((unsigned short)atoi(service))) == 0) 86 errexit("can't get \"%s\" service entry\n", service); 87 88 /* Map host name to IP address, allowing for dotted decimal */ 89 if ( phe = gethostbyname(host) ) 90 memcpy(&sin.sin_addr, phe->h_addr, phe->h_length); 91 else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE ) 92 errexit("can't get \"%s\" host entry\n", host); 93 94 /* Map transport protocol name to protocol number */ 95 if ( (ppe = getprotobyname(transport)) == 0) 96 errexit("can't get \"%s\" protocol entry\n", transport); 97 98 /* Use protocol to choose a socket type */ 99 if (strcmp(transport, "udp") == 0) 100 type = SOCK_DGRAM; 101 else 102 type = SOCK_STREAM; 103 104 /* Allocate a socket */ 105 s = socket(PF_INET, type, ppe->p_proto); 106 if (s < 0) 107 errexit("can't create socket: %s\n", strerror(errno)); 108 109 /* Connect the socket */ 110 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) 111 errexit("can't connect to %s.%s: %s\n", host, service, 112 strerror(errno)); 113 return s; 114 } 115 int connectTCP(const char *host, const char *service){ 116 return connectsock(host,service,"tcp"); 117 }
二、针对echo服务的并发的面向连接的服务器软件的实现
1.网络拓扑结构:
2.源码:
1 #define _USE_BSD 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <string.h> 6 #include <stdarg.h> 7 #include <sys/types.h> 8 #include <sys/socket.h> 9 #include <netinet/in.h> 10 #include <arpa/inet.h> 11 #include <netdb.h> 12 #include <signal.h> 13 #include <errno.h> 14 15 #define QLEN 32 16 #define BUFSIZE 4096 17 extern int errno; 18 unsigned short portbase = 0; 19 20 void reaper(int); 21 int TCPechod(int fd); 22 int errexit(const char *format,...); 23 int passivesock(const char *service, const char *transport, int qlen); 24 int passiveTCP(const char *service,int qlen); 25 26 int main(int argc, char *argv[]){ 27 char *service= "echo"; 28 struct sockaddr_in fsin; 29 unsigned int alen; 30 int msock,ssock; 31 switch(argc){ 32 case 1: 33 break; 34 case 2: 35 service=argv[1]; 36 break; 37 default: 38 errexit("usage: TCPechod [port]\n"); 39 } 40 41 msock=passiveTCP(service,QLEN); 42 (void)signal(SIGCHLD,(__sighandler_t)QLEN); 43 44 while(1){ 45 alen=sizeof(fsin); 46 ssock=accept(msock,(struct sockaddr *)&fsin,&alen); 47 if(ssock<0){ 48 if(errno==EINTR) continue; 49 errexit("accept: %s\n",strerror(errno)); 50 } 51 switch(fork()){ 52 case 0: 53 (void)close(msock); 54 exit(TCPechod(ssock)); 55 default: 56 (void)close(ssock); 57 break; 58 case -1: 59 errexit("fork: %s\n",strerror(errno)); 60 } 61 } 62 } 63 64 void reaper(int sig){ 65 int status; 66 while(wait3(&status,WNOHANG,(struct rusage *)0)>=0) ; 67 } 68 int TCPechod(int fd){ 69 char buf[BUFSIZ]; 70 int cc; 71 72 while(cc=read(fd,buf,sizeof(buf))){ 73 if(cc<0) 74 errexit("echo read: %s\n",strerror(errno)); 75 if(write(fd,buf,cc)<0) 76 errexit("echo write: %s\n",strerror(errno)); 77 } 78 return 0; 79 } 80 int errexit(const char *format,...){ 81 va_list arg; 82 va_start(arg, format); 83 vfprintf(stderr,format,arg); 84 va_end(arg); 85 exit(1); 86 } 87 int passivesock(const char *service, const char *transport, int qlen) 88 /* 89 * Arguments: 90 * service - service associated with the desired port 91 * transport - transport protocol to use ("tcp" or "udp") 92 * qlen - maximum server request queue length 93 */ 94 { 95 96 struct servent*pse;/* pointer to service information entry*/ 97 struct protoent *ppe;/* pointer to protocol information entry*/ 98 struct sockaddr_in sin;/* an Internet endpoint address*/ 99 int s, type;/* socket descriptor and socket type*/ 100 101 memset(&sin, 0, sizeof(sin)); 102 sin.sin_family = AF_INET; 103 sin.sin_addr.s_addr = INADDR_ANY; 104 105 /* Map service name to port number */ 106 if ( pse = getservbyname(service, transport) ) 107 sin.sin_port = htons(ntohs((unsigned short)pse->s_port)+ portbase); 108 else 109 if ((sin.sin_port=htons((unsigned short)atoi(service)+portbase)) == 0) 110 errexit("can't create passive service %d \n",sin.sin_port); 111 112 /* Map protocol name to protocol number */ 113 if ( (ppe = getprotobyname(transport)) == 0) 114 errexit("can't get \"%s\" protocol entry\n", transport); 115 116 /* Use protocol to choose a socket type */ 117 if (strcmp(transport, "udp") == 0) 118 type = SOCK_DGRAM; 119 else 120 type = SOCK_STREAM; 121 122 /* Allocate a socket */ 123 s = socket(PF_INET, type, ppe->p_proto); 124 if (s < 0) 125 errexit("can't create socket: %s\n", strerror(errno)); 126 127 /* Bind the socket */ 128 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) 129 errexit("can't bind to %s port: %s\n", service, 130 strerror(errno)); 131 if (type == SOCK_STREAM && listen(s, qlen) < 0) 132 errexit("can't listen on %s port: %s\n", service, 133 strerror(errno)); 134 return s; 135 } 136 int passiveTCP(const char *service,int qlen){ 137 return passivesock(service,"tcp",qlen); 138 }
三、针对TIME服务的UDP客户软件的实现
1.网络拓扑结构:
2.源码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <string.h> 5 #include <stdarg.h> 6 #include <sys/types.h> 7 #include <sys/socket.h> 8 #include <netinet/in.h> 9 #include <arpa/inet.h> 10 #include <netdb.h> 11 #include <time.h> 12 #include <errno.h> 13 14 #define BUFSIZE 64 15 #define UNIXEPOCH 2208988800UL 16 #define MSG "what time is it?\n" 17 extern int errno; 18 19 int errexit(const char *format,...); 20 int connectsock(const char *host, const char *service, const char *transport ); 21 int connectUDP(const char *host, const char *service); 22 23 int main(int argc, char *argv[]){ 24 char *host= "localhost"; 25 char *service= "time"; 26 time_t now; 27 int s,n; 28 29 switch(argc){ 30 case 1: 31 host = "localhost"; 32 break; 33 case 3: 34 service = argv[2]; 35 case 2: 36 host=argv[1]; 37 break; 38 default: 39 fprintf(stderr,"usage: UDPtime[host[port]]\n"); 40 exit(1); 41 } 42 43 s=connectUDP(host,service); 44 (void)write(s,MSG,strlen(MSG)); 45 46 n=read(s,(char *)&now,sizeof(now)); 47 if(n<0) errexit("read failed: %s\n",strerror(errno)); 48 now=ntohl((unsigned long)now); 49 now-=UNIXEPOCH; 50 printf("%s",ctime(&now)); 51 exit(0); 52 } 53 int errexit(const char *format,...){ 54 va_list arg; 55 va_start(arg, format); 56 vfprintf(stderr,format,arg); 57 va_end(arg); 58 exit(1); 59 } 60 int connectsock(const char *host, const char *service, const char *transport ) 61 /* 62 * Arguments: 63 * host - name of host to which connection is desired 64 * service - service associated with the desired port 65 * transport - name of transport protocol to use ("tcp" or "udp") 66 */ 67 { 68 struct hostent *phe; /* pointer to host information entry */ 69 struct servent *pse; /* pointer to service information entry */ 70 struct protoent *ppe; /* pointer to protocol information entry*/ 71 struct sockaddr_in sin; /* an Internet endpoint address */ 72 int s, type; /* socket descriptor and socket type */ 73 74 75 memset(&sin, 0, sizeof(sin)); 76 sin.sin_family = AF_INET; 77 78 /* Map service name to port number */ 79 if ( pse = getservbyname(service, transport) ) 80 sin.sin_port = pse->s_port; 81 else if ((sin.sin_port=htons((unsigned short)atoi(service))) == 0) 82 errexit("can't get \"%s\" service entry\n", service); 83 84 /* Map host name to IP address, allowing for dotted decimal */ 85 if ( phe = gethostbyname(host) ) 86 memcpy(&sin.sin_addr, phe->h_addr, phe->h_length); 87 else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE ) 88 errexit("can't get \"%s\" host entry\n", host); 89 90 /* Map transport protocol name to protocol number */ 91 if ( (ppe = getprotobyname(transport)) == 0) 92 errexit("can't get \"%s\" protocol entry\n", transport); 93 94 /* Use protocol to choose a socket type */ 95 if (strcmp(transport, "udp") == 0) 96 type = SOCK_DGRAM; 97 else 98 type = SOCK_STREAM; 99 100 /* Allocate a socket */ 101 s = socket(PF_INET, type, ppe->p_proto); 102 if (s < 0) 103 errexit("can't create socket: %s\n", strerror(errno)); 104 105 /* Connect the socket */ 106 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) 107 errexit("can't connect to %s.%s: %s\n", host, service, 108 strerror(errno)); 109 return s; 110 } 111 int connectUDP(const char *host, const char *service){ 112 return connectsock(host,service,"udp"); 113 }
四、针对TIME服务的UDP服务器端软件的实现
1.网络拓扑结构:
2.源码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <string.h> 5 #include <stdarg.h> 6 #include <sys/types.h> 7 #include <sys/socket.h> 8 #include <netinet/in.h> 9 #include <arpa/inet.h> 10 #include <netdb.h> 11 #include <errno.h> 12 13 #define UNIXEPOCH 2208988800UL 14 15 extern int errno; 16 unsigned short portbase = 0; 17 18 int errexit(const char *format,...); 19 int passivesock(const char *service, const char *transport, int qlen); 20 int passiveUDP(const char *service); 21 22 int main(int argc, char *argv[]){ 23 char *service= "time"; 24 struct sockaddr_in fsin; 25 char buf[1]; 26 int sock; 27 time_t now; 28 unsigned int alen; 29 30 switch(argc){ 31 case 1: 32 break; 33 case 2: 34 service=argv[1]; 35 break; 36 default: 37 errexit("usage: UDPtimed [port]\n"); 38 } 39 40 sock=passiveUDP(service); 41 42 while(1){ 43 alen=sizeof(fsin); 44 if(recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr *)&fsin,&alen)<0) 45 errexit("recvfrom: %s\n",strerror(errno)); 46 (void)time(&now); 47 now=htonl((unsigned long)(now+UNIXEPOCH)); 48 (void)sendto(sock,(char*)&now,sizeof(now),0,(struct sockaddr *)&fsin,sizeof(fsin)); 49 } 50 } 51 52 int errexit(const char *format,...){ 53 va_list arg; 54 va_start(arg, format); 55 vfprintf(stderr,format,arg); 56 va_end(arg); 57 exit(1); 58 } 59 int passivesock(const char *service, const char *transport, int qlen) 60 /* 61 * Arguments: 62 * service - service associated with the desired port 63 * transport - transport protocol to use ("tcp" or "udp") 64 * qlen - maximum server request queue length 65 */ 66 { 67 68 struct servent*pse;/* pointer to service information entry*/ 69 struct protoent *ppe;/* pointer to protocol information entry*/ 70 struct sockaddr_in sin;/* an Internet endpoint address*/ 71 int s, type;/* socket descriptor and socket type*/ 72 73 memset(&sin, 0, sizeof(sin)); 74 sin.sin_family = AF_INET; 75 sin.sin_addr.s_addr = INADDR_ANY; 76 77 /* Map service name to port number */ 78 if ( pse = getservbyname(service, transport) ) 79 sin.sin_port = htons(ntohs((unsigned short)pse->s_port)+ portbase); 80 else 81 if ((sin.sin_port=htons((unsigned short)atoi(service)+portbase)) == 0) 82 errexit("can't create passive service %d \n",sin.sin_port); 83 84 /* Map protocol name to protocol number */ 85 if ( (ppe = getprotobyname(transport)) == 0) 86 errexit("can't get \"%s\" protocol entry\n", transport); 87 88 /* Use protocol to choose a socket type */ 89 if (strcmp(transport, "udp") == 0) 90 type = SOCK_DGRAM; 91 else 92 type = SOCK_STREAM; 93 94 /* Allocate a socket */ 95 s = socket(PF_INET, type, ppe->p_proto); 96 if (s < 0) 97 errexit("can't create socket: %s\n", strerror(errno)); 98 99 /* Bind the socket */ 100 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) 101 errexit("can't bind to %s port: %s\n", service, 102 strerror(errno)); 103 if (type == SOCK_STREAM && listen(s, qlen) < 0) 104 errexit("can't listen on %s port: %s\n", service, 105 strerror(errno)); 106 return s; 107 } 108 int passiveUDP(const char *service){ 109 return passivesock(service,"udp",0); 110 }
这里是用的我实验时的代码,前两个是关于echo服务的客户端与服务器端,有下面运行截图:
后两个是关于time服务的,有下面运行截图:
实验时由于多次运行验证,总会出现端口占用的情况,于是这里每次运行时都输入程序的入口参数(就是main函数里的形参),自选端口,方便至极。还有就是代码里多个函数可以写入多个cpp里,这里偷懒了。