用TCP/TP进行网际互连(7) ———— 支持多协议多服务的服务器设计和实现
来源:互联网 发布:足球数据app 编辑:程序博客网 时间:2024/05/20 00:36
用TCP/TP进行网际互连(7)
———— 支持多协议多服务的服务器设计和实现
融合之前实现的各种协议与服务的代码,实现一个支持多协议多服务的服务器。
1、实现过程
- 服务器:
- errexit.c、passivesock.c、passiveTCP.c、passiveUDP.c分别是之前对相应过程代码的封装。
- superd.c :在初始化数据结构并为它所提供的每个服务打开套接字之后,服务器主程序便进入了无限循环。每一次循环都调用select,以便等待各套接字中的某个准备就绪。当请求到达时,select就返回。
- sv_funcs.c :是一些提供的服务的具体实现,包含TCPechod(int), TCPchargend(int), TCPdaytimed(int), TCPtimed(int), UDPechod(int), UDPtimed(int);
这里只贴一下主要代码,全部代码已上传github,有兴趣可以拿来看一下:
https://github.com/KevinBetterQ/Network-programming/tree/master/All/S
//superd.c :int main(int argc, char *argv[]){ struct service *psv, /* service table pointer */ *fd2sv[NOFILE]; /* map fd to service pointer */ int fd, nfds; fd_set afds, rfds; /* readable file descriptors */ switch (argc) { case 1: break; case 2: portbase = (unsigned short) atoi(argv[1]); break; default: errexit("usage: superd [portbase]\n"); } nfds = 0; FD_ZERO(&afds); for (psv = &svent[0]; psv->sv_name; ++psv) { if (psv->sv_useTCP) psv->sv_sock = passiveTCP(psv->sv_name, QLEN); else psv->sv_sock = passiveUDP(psv->sv_name); fd2sv[psv->sv_sock] = psv; nfds = MAX(psv->sv_sock+1, nfds); FD_SET(psv->sv_sock, &afds); } (void) signal(SIGCHLD, reaper); while (1) { memcpy(&rfds, &afds, sizeof(rfds)); if (select(nfds, &rfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) { if (errno == EINTR) continue; errexit("select error: %s\n", strerror(errno)); } for (fd=0; fd<nfds; ++fd) if (FD_ISSET(fd, &rfds)) { psv = fd2sv[fd]; if (psv->sv_useTCP) doTCP(psv); else psv->sv_func(psv->sv_sock); } }}/*------------------------------------------------------------------------ * doTCP - handle a TCP service connection request *------------------------------------------------------------------------ */voiddoTCP(struct service *psv){ struct sockaddr_in fsin; /* the request from address */ unsigned int alen; /* from-address length */ int fd, ssock; alen = sizeof(fsin); ssock = accept(psv->sv_sock, (struct sockaddr *)&fsin, &alen); if (ssock < 0) errexit("accept: %s\n", strerror(errno)); switch (fork()) { case 0: break; case -1: errexit("fork: %s\n", strerror(errno)); default: (void) close(ssock); return; /* parent */ } /* child */ for (fd = NOFILE; fd >= 0; --fd) if (fd != ssock) (void) close(fd); psv->sv_func(ssock); exit(0);}
//sv_funcs.c:void TCPechod(int fd){ char buf[BUFFERSIZE]; 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)); }}voidUDPechod(int sock){ struct sockaddr_in fsin; /* the from address of a client */ char buf[128]; /* "input" buffer; any size > 0 */ time_t now; /* current time */ unsigned int alen; /* from-address length */ int n; /*接收数据长度*/ alen = sizeof(fsin); n = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&fsin, &alen); (void) sendto(sock, buf, n, 0, (struct sockaddr *)&fsin, sizeof(fsin));}/*------------------------------------------------------------------------ * TCPdaytimed - do TCP DAYTIME protocol *------------------------------------------------------------------------ */voidTCPdaytimed(int fd){ char buf[LINELEN], *ctime(); time_t now; (void) time(&now); sprintf(buf, "%s", ctime(&now)); (void) write(fd, buf, strlen(buf));}#define UNIXEPOCH 2208988800UL /* UNIX epoch, in UCT secs */voidTCPtimed(int fd){ time_t now; (void) time(&now); now = htonl((unsigned long)(now + UNIXEPOCH)); (void) write(fd, (char *)&now, sizeof(now));}voidUDPtimed(int sock){ struct sockaddr_in fsin; /* the from address of a client */ char buf[1]; /* "input" buffer; any size > 0 */ time_t now; /* current time */ unsigned int alen; /* from-address length */ 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));}
- 客户端
- connectsock.c、connectTCP.c、connectUDP.c、errexit.c分别是之前对相应过程代码的封装。
- TCPdaytime.c、TCPecho.c、UDPecho.c、UDPtime.c分别对象文件名的相应协议与服务。
下面也只放一下主要功能代码部分,全部代码可以参考:
https://github.com/KevinBetterQ/Network-programming/tree/master/All/C
//TCPdaytime.c/*------------------------------------------------------------------------ * TCPdaytime - invoke Daytime on specified host and print results *------------------------------------------------------------------------ */TCPdaytime(const char *host, const char *service){ char buf[LINELEN+1]; /* buffer for one line of text */ int s, n; /* socket, read count */ s = connectTCP(host, service); while( (n = read(s, buf, LINELEN)) > 0) { buf[n] = '\0'; /* ensure null-terminated */ (void) fputs( buf, stdout ); }}
//TCPecho.cint TCPecho(const char *host, const char *service){ char buf[LINELEN+1]; /* buffer for one line of text */ int s, n; /* socket descriptor, read count*/ int outchars, inchars; /* characters sent and received */ s = connectTCP(host, service); while (fgets(buf, sizeof(buf), stdin)) { buf[LINELEN] = '\0'; /* insure line null-terminated */ outchars = strlen(buf); (void) write(s, buf, outchars); /* read it back */ for (inchars = 0; inchars < outchars; inchars+=n ) { n = read(s, &buf[inchars], outchars - inchars); if (n < 0) errexit("socket read failed: %s\n", strerror(errno)); } fputs(buf, stdout); }}
//UDPecho.cint UDPecho(const char *host, const char *service){ char buf[LINELEN+1]; /* buffer for one line of text */ int s, nchars; /* socket descriptor, read count*/ s = connectUDP(host, service); while (fgets(buf, sizeof(buf), stdin)) { buf[LINELEN] = '\0'; /* insure null-terminated */ nchars = strlen(buf); (void) write(s, buf, nchars); if (read(s, buf, nchars) < 0) errexit("socket read failed: %s\n", strerror(errno)); fputs(buf, stdout); }}
//UDPtime.cint main(int argc, char *argv[]){ char *host = "localhost"; /* host to use if none supplied */ char *service = "time"; /* default service name */ time_t now; /* 32-bit integer to hold time */ int s, n; /* socket descriptor, read count*/ switch (argc) { case 1: host = "localhost"; break; case 3: service = argv[2]; /* FALL THROUGH */ 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)); /* Read the time */ n = read(s, (char *)&now, sizeof(now)); if (n < 0) errexit("read failed: %s\n", strerror(errno)); now = ntohl((unsigned long)now); /* put in host order */ now -= UNIXEPOCH; /* convert UCT to UNIX epoch */ printf("%s", ctime(&now)); exit(0);}
2、效果展示
开启服务器::
客户端连接:
可以看到两种协议的四个服务都可以实现了。
阅读全文
1 0
- 用TCP/TP进行网际互连(7) ———— 支持多协议多服务的服务器设计和实现
- 用TCP/TP进行网际互连(5) ———— 多进程和多线程实现服务器端的并发处理
- 用TCP/TP进行网际互连(6) ———— 利用I/O复用完成单进程并发服务器的处理
- 9、10章:CIDR和协议的分层 - 用TCP/IP进行网际互连
- 6、7、8章:IP协议及IP数据报转发和ICMP - 用TCP/IP进行网际互连
- 10、11章:UDP和TCP - 用TCP/IP进行网际互连
- 互连网协议——TCP/IP
- 4、5章:分类互联网地址和ARP - 用TCP/IP进行网际互连
- 使用TCP/IP进行网际互连 --- 确认、重传和超时
- TCP/IP协议族——网际控制报文协议ICMP
- MIME —— 多用途的网际邮件扩充协议
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
- 《TCP/IP入门经典》——网际层
- 理解TCP/IP网际层——ABCDE类
- map
- 编辑距离问题
- vue.js移动端app实战1:初始配置
- 2017/8/10训练日记
- 梯度下降(Gradient Descent)
- 用TCP/TP进行网际互连(7) ———— 支持多协议多服务的服务器设计和实现
- mybatis框架中动态sql的应用
- 开发声卡驱动移植
- setTimeout立即执行,没有延迟效果
- HDU I Hate It(树状数组)
- leetcode --8. String to Integer (atoi)
- 用bootstrip敲一个计算器
- Cortex M3寄存器组
- 快速排序法排序