一、針對ECHO服務的TCP客戶軟件的實現
1.網絡拓撲結構:
2.源碼:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#define LINELEN 128
extern int errno;
int TCPecho(const char *host, const char *service);
int errexit(const char *format,...);
int connectsock(const char *host, const char *service, const char *transport );
int connectTCP(const char *host, const char *service);
int main(int argc, char *argv[]){
char *host= "localhost";
char *service= "echo";
switch(argc){
case 1:
host = "localhost";
break;
case 3:
service = argv[2];
case 2:
host=argv[1];
break;
default:
fprintf(stderr,"usage:TCPecho[host[port]]\n");
exit(1);
}
TCPecho(host,service);
exit(0);
}
int TCPecho(const char *host,const char *service){
char buf[LINELEN+1];
int s,n;
int outchars, inchars;
s=connectTCP(host, service);
while(fgets(buf,sizeof(buf),stdin)){
buf[LINELEN]='\0';
outchars=strlen(buf);
(void)write(s,buf,outchars);
for(inchars=0;inchars<outchars;inchars+=n){
n=read(s,&buf[inchars],outchars-inchars);
if(n<0)
errexit("socker read failed: %s\n",strerror(errno));
}
fputs(buf,stdout);
}
}
int errexit(const char *format,...){
va_list arg;
va_start(arg, format);
vfprintf(stderr,format,arg);
va_end(arg);
exit(1);
}
int connectsock(const char *host, const char *service, const char *transport )
/*
* Arguments:
* host - name of host to which connection is desired
* service - service associated with the desired port
* transport - name of transport protocol to use ("tcp" or "udp")
*/
{
struct hostent *phe; /* pointer to host information entry */
struct servent *pse; /* pointer to service information entry */
struct protoent *ppe; /* pointer to protocol information entry*/
struct sockaddr_in sin; /* an Internet endpoint address */
int s, type; /* socket descriptor and socket type */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
/* Map service name to port number */
if ( pse = getservbyname(service, transport) )
sin.sin_port = pse->s_port;
else if ((sin.sin_port=htons((unsigned short)atoi(service))) == 0)
errexit("can't get \"%s\" service entry\n", service);
/* Map host name to IP address, allowing for dotted decimal */
if ( phe = gethostbyname(host) )
memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )
errexit("can't get \"%s\" host entry\n", host);
/* Map transport protocol name to protocol number */
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/* Use protocol to choose a socket type */
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if (s < 0)
errexit("can't create socket: %s\n", strerror(errno));
/* Connect the socket */
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
errexit("can't connect to %s.%s: %s\n", host, service,
strerror(errno));
return s;
}
int connectTCP(const char *host, const char *service){
return connectsock(host,service,"tcp");
}
二、針對echo服務的並發的面向連接的服務器軟件的實現
1.網絡拓撲結構:
2.源碼:
#define _USE_BSD
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>
#define QLEN 32
#define BUFSIZE 4096
extern int errno;
unsigned short portbase = 0;
void reaper(int);
int TCPechod(int fd);
int errexit(const char *format,...);
int passivesock(const char *service, const char *transport, int qlen);
int passiveTCP(const char *service,int qlen);
int main(int argc, char *argv[]){
char *service= "echo";
struct sockaddr_in fsin;
unsigned int alen;
int msock,ssock;
switch(argc){
case 1:
break;
case 2:
service=argv[1];
break;
default:
errexit("usage: TCPechod [port]\n");
}
msock=passiveTCP(service,QLEN);
(void)signal(SIGCHLD,(__sighandler_t)QLEN);
while(1){
alen=sizeof(fsin);
ssock=accept(msock,(struct sockaddr *)&fsin,&alen);
if(ssock<0){
if(errno==EINTR) continue;
errexit("accept: %s\n",strerror(errno));
}
switch(fork()){
case 0:
(void)close(msock);
exit(TCPechod(ssock));
default:
(void)close(ssock);
break;
case -1:
errexit("fork: %s\n",strerror(errno));
}
}
}
void reaper(int sig){
int status;
while(wait3(&status,WNOHANG,(struct rusage *)0)>=0) ;
}
int TCPechod(int fd){
char buf[BUFSIZ];
int cc;
while(cc=read(fd,buf,sizeof(buf))){
if(cc<0)
errexit("echo read: %s\n",strerror(errno));
if(write(fd,buf,cc)<0)
errexit("echo write: %s\n",strerror(errno));
}
return 0;
}
int errexit(const char *format,...){
va_list arg;
va_start(arg, format);
vfprintf(stderr,format,arg);
va_end(arg);
exit(1);
}
int passivesock(const char *service, const char *transport, int qlen)
/*
* Arguments:
* service - service associated with the desired port
* transport - transport protocol to use ("tcp" or "udp")
* qlen - maximum server request queue length
*/
{
struct servent*pse;/* pointer to service information entry*/
struct protoent *ppe;/* pointer to protocol information entry*/
struct sockaddr_in sin;/* an Internet endpoint address*/
int s, type;/* socket descriptor and socket type*/
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
/* Map service name to port number */
if ( pse = getservbyname(service, transport) )
sin.sin_port = htons(ntohs((unsigned short)pse->s_port)+ portbase);
else
if ((sin.sin_port=htons((unsigned short)atoi(service)+portbase)) == 0)
errexit("can't create passive service %d \n",sin.sin_port);
/* Map protocol name to protocol number */
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/* Use protocol to choose a socket type */
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if (s < 0)
errexit("can't create socket: %s\n", strerror(errno));
/* Bind the socket */
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
errexit("can't bind to %s port: %s\n", service,
strerror(errno));
if (type == SOCK_STREAM && listen(s, qlen) < 0)
errexit("can't listen on %s port: %s\n", service,
strerror(errno));
return s;
}
int passiveTCP(const char *service,int qlen){
return passivesock(service,"tcp",qlen);
}
三、針對TIME服務的UDP客戶軟件的實現
1.網絡拓撲結構:
2.源碼:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <errno.h>
#define BUFSIZE 64
#define UNIXEPOCH 2208988800UL
#define MSG "what time is it?\n"
extern int errno;
int errexit(const char *format,...);
int connectsock(const char *host, const char *service, const char *transport );
int connectUDP(const char *host, const char *service);
int main(int argc, char *argv[]){
char *host= "localhost";
char *service= "time";
time_t now;
int s,n;
switch(argc){
case 1:
host = "localhost";
break;
case 3:
service = argv[2];
case 2:
host=argv[1];
break;
default:
fprintf(stderr,"usage: UDPtime[host[port]]\n");
exit(1);
}
s=connectUDP(host,service);
(void)write(s,MSG,strlen(MSG));
n=read(s,(char *)&now,sizeof(now));
if(n<0) errexit("read failed: %s\n",strerror(errno));
now=ntohl((unsigned long)now);
now-=UNIXEPOCH;
printf("%s",ctime(&now));
exit(0);
}
int errexit(const char *format,...){
va_list arg;
va_start(arg, format);
vfprintf(stderr,format,arg);
va_end(arg);
exit(1);
}
int connectsock(const char *host, const char *service, const char *transport )
/*
* Arguments:
* host - name of host to which connection is desired
* service - service associated with the desired port
* transport - name of transport protocol to use ("tcp" or "udp")
*/
{
struct hostent *phe; /* pointer to host information entry */
struct servent *pse; /* pointer to service information entry */
struct protoent *ppe; /* pointer to protocol information entry*/
struct sockaddr_in sin; /* an Internet endpoint address */
int s, type; /* socket descriptor and socket type */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
/* Map service name to port number */
if ( pse = getservbyname(service, transport) )
sin.sin_port = pse->s_port;
else if ((sin.sin_port=htons((unsigned short)atoi(service))) == 0)
errexit("can't get \"%s\" service entry\n", service);
/* Map host name to IP address, allowing for dotted decimal */
if ( phe = gethostbyname(host) )
memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )
errexit("can't get \"%s\" host entry\n", host);
/* Map transport protocol name to protocol number */
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/* Use protocol to choose a socket type */
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if (s < 0)
errexit("can't create socket: %s\n", strerror(errno));
/* Connect the socket */
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
errexit("can't connect to %s.%s: %s\n", host, service,
strerror(errno));
return s;
}
int connectUDP(const char *host, const char *service){
return connectsock(host,service,"udp");
}
四、針對TIME服務的UDP服務器端軟件的實現
1.網絡拓撲結構:
2.源碼:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#define UNIXEPOCH 2208988800UL
extern int errno;
unsigned short portbase = 0;
int errexit(const char *format,...);
int passivesock(const char *service, const char *transport, int qlen);
int passiveUDP(const char *service);
int main(int argc, char *argv[]){
char *service= "time";
struct sockaddr_in fsin;
char buf[1];
int sock;
time_t now;
unsigned int alen;
switch(argc){
case 1:
break;
case 2:
service=argv[1];
break;
default:
errexit("usage: UDPtimed [port]\n");
}
sock=passiveUDP(service);
while(1){
alen=sizeof(fsin);
if(recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr *)&fsin,&alen)<0)
errexit("recvfrom: %s\n",strerror(errno));
(void)time(&now);
now=htonl((unsigned long)(now+UNIXEPOCH));
(void)sendto(sock,(char*)&now,sizeof(now),0,(struct sockaddr *)&fsin,sizeof(fsin));
}
}
int errexit(const char *format,...){
va_list arg;
va_start(arg, format);
vfprintf(stderr,format,arg);
va_end(arg);
exit(1);
}
int passivesock(const char *service, const char *transport, int qlen)
/*
* Arguments:
* service - service associated with the desired port
* transport - transport protocol to use ("tcp" or "udp")
* qlen - maximum server request queue length
*/
{
struct servent*pse;/* pointer to service information entry*/
struct protoent *ppe;/* pointer to protocol information entry*/
struct sockaddr_in sin;/* an Internet endpoint address*/
int s, type;/* socket descriptor and socket type*/
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
/* Map service name to port number */
if ( pse = getservbyname(service, transport) )
sin.sin_port = htons(ntohs((unsigned short)pse->s_port)+ portbase);
else
if ((sin.sin_port=htons((unsigned short)atoi(service)+portbase)) == 0)
errexit("can't create passive service %d \n",sin.sin_port);
/* Map protocol name to protocol number */
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/* Use protocol to choose a socket type */
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if (s < 0)
errexit("can't create socket: %s\n", strerror(errno));
/* Bind the socket */
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
errexit("can't bind to %s port: %s\n", service,
strerror(errno));
if (type == SOCK_STREAM && listen(s, qlen) < 0)
errexit("can't listen on %s port: %s\n", service,
strerror(errno));
return s;
}
int passiveUDP(const char *service){
return passivesock(service,"udp",0);
}
這裡是用的我實驗時的代碼,前兩個是關於echo服務的客戶端與服務器端,有下面運行截圖:
後兩個是關於time服務的,有下面運行截圖:
實驗時由於多次運行驗證,總會出現端口占用的情況,於是這裡每次運行時都輸入程序的入口參數(就是main函數裡的形參),自選端口,方便至極。還有就是代碼裡多個函數可以寫入多個cpp裡,這裡偷懶了。