用TCP/TP进行网际互连(6) ———— 利用I/O复用完成单进程并发服务器的处理
来源:互联网 发布:软件性质 编辑:程序博客网 时间:2024/05/08 02:44
用TCP/TP进行网际互连(6)
———— 利用I/O复用完成单进程并发服务器的处理
1、实现原理
1)创建套接字并将其绑定到这个服务的熟知端口上,将该套接字加到一个表中,该表中的项是可以进行I/O的描述符。
2)使用select在已经有的套接字上等待I/O。
3)如果最初的套接字准备就绪,使用accept获得下一个连接,并将这个新的套接字加入到表中,该表中的项是可以进行I/O的描述符。
4)如果最初的套接字以外的套接字就绪,就使用recv或read获得下一个请求,构造响应,用send或者write将响应发回给客户。
5)继续按照以上的步骤2进行处理。
2、代码实现
- 服务器:
#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#include <unistd.h>#include <string.h>#include <stdio.h>#include <errno.h>#define PORT 6000#define LISTENQ 20#define BUFFSIZE 4096#define FILE_NAME_MAX_SIZE 512int echo(int sc){ //process_conn_server(sc); /*处理连接*/ ssize_t size = 0; char buffer[1024]; /*数据的缓冲区*/ size = read(sc, buffer, 1024); /*从套接字中读取数据放到 缓冲区buffer中*/ write(sc, buffer, strlen(buffer)+1);/*发给客户端*/ return size;}int passiveTCP (const char*service){ //Create socket int sockfd,connfd; struct sockaddr_in svraddr,clientaddr; bzero(&svraddr,sizeof(svraddr)); svraddr.sin_family=AF_INET; svraddr.sin_addr.s_addr=htonl(INADDR_ANY); svraddr.sin_port=htons(PORT); sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd<0) { perror("socket"); exit(1); } //bind if(bind(sockfd,(struct sockaddr*)&svraddr,sizeof(svraddr))<0) { perror("bind"); exit(1); } //listen if(listen(sockfd,LISTENQ)<0) { perror("listen"); exit(1); } return sockfd;}int main(int argc, char *argv[]){ char *service = "echo";/* service name or port number*/ struct sockaddr_in fsin; /* the from address of a client */ int msock; /* master server socket */ fd_set rfds; /* read file descriptor set */ fd_set afds; /* active file descriptor set */ unsigned int alen; /* from-address length */ int fd, nfds; msock = passiveTCP(service); nfds = getdtablesize(); FD_ZERO(&afds); FD_SET(msock, &afds); while (1) { memcpy(&rfds, &afds, sizeof(rfds)); if (select(nfds, &rfds, (fd_set *)0, (fd_set *)0,(struct timeval *)0) < 0) //errexit("select: %s\n", strerror(errno)); printf("select error"); if (FD_ISSET(msock, &rfds)) { int ssock; alen = sizeof(fsin); ssock = accept(msock, (struct sockaddr *)&fsin,&alen); if (ssock < 0) //errexit("accept: %s\n",strerror(errno)); printf("accept error"); FD_SET(ssock, &afds); } for (fd=0; fd<nfds; ++fd) if (fd != msock && FD_ISSET(fd, &rfds)) if (echo(fd) == 0) { close(fd); FD_CLR(fd, &afds); }}}
- 客户端
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <arpa/inet.h>#define PORT 6000 /*侦听端口地址*/#define IP "127.0.0.1" /*服务器IP地址*/int main(int argc, char *argv[]){ int s; /*s为socket描述符*/ struct sockaddr_in server_addr; /*服务器地址结构*/ s = socket(AF_INET, SOCK_STREAM, 0); /*建立一个流式套接字 */ if(s < 0){ /*出错*/ printf("socket error\n"); return -1; } /*设置服务器地址*/ bzero(&server_addr, sizeof(server_addr)); /*清零*/ server_addr.sin_family = AF_INET; /*协议族*/ server_addr.sin_addr.s_addr = htonl(INADDR_ANY); /*本地地址*/ server_addr.sin_port = htons(PORT); /*服务器端口*/ /*将用户输入的字符串类型的IP地址转为整型*/ inet_pton(AF_INET, IP, &server_addr.sin_addr); /*连接服务器*/ connect(s, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)); //process_conn_client(s); /*客户端处理过程*/ ssize_t size = 0; char buffer[1024]; /*数据的缓冲区*/ for(;;){ /*循环处理过程*/ /*从标准输入中读取数据放到缓冲区buffer中*/ size = read(0, buffer, 1024); if(size > 0){ /*读到数据*/ write(s, buffer, size); /*发送给服务器*/ size = read(s, buffer, 1024); /*从服务器读取数据*/ write(1, buffer, size); /*写到标准输出*/ } } close(s); /*关闭连接*/ return 0;}
3、运行效果
服务器:
打开三个客户端同时连接:
可以看到,服务器可以对这三个客户端并发提供服务。
附上我的实验代码,有兴趣可以拿来看一下:
https://github.com/KevinBetterQ/Network-programming/tree/master/select
阅读全文
1 0
- 用TCP/TP进行网际互连(6) ———— 利用I/O复用完成单进程并发服务器的处理
- 用TCP/TP进行网际互连(5) ———— 多进程和多线程实现服务器端的并发处理
- 用TCP/TP进行网际互连(7) ———— 支持多协议多服务的服务器设计和实现
- Linux网络编程——tcp并发服务器(I/O复用之select)
- Linux网络编程——tcp并发服务器(I/O复用之select)
- Linux网络编程——tcp并发服务器(I/O复用之select
- 9、10章:CIDR和协议的分层 - 用TCP/IP进行网际互连
- UNIX网络编程——shutdown函数(I/O复用并发服务器)
- I/O复用实现单线程并发服务器
- 10、11章:UDP和TCP - 用TCP/IP进行网际互连
- 6、7、8章:IP协议及IP数据报转发和ICMP - 用TCP/IP进行网际互连
- 使用Select I/O模型来实现一个并发处理多个客户端的TCP服务器
- Select I/O模型来实现一个并发处理多个客户端的TCP服务器
- Linux网络编程:tcp并发服务器(I/O复用之select)
- 4、5章:分类互联网地址和ARP - 用TCP/IP进行网际互连
- Linux网络编程--单进程服务器处理多客户请求(I/O复用)
- UNIX网络编程——并发服务器(I/O复用)
- Linux系统编程(35)—— socket编程之TCP服务器的并发处理
- mybatis解决数据库表列明与实体不一致问题
- ubuntu14.04源码安装tensorflow
- spring mvc基础篇(六):Spring mvc之拦截器
- Java知识(访问修饰符、方法重写和方法重载的区别以及java抽象)
- 2017 Multi-University Training Contest
- 用TCP/TP进行网际互连(6) ———— 利用I/O复用完成单进程并发服务器的处理
- ARP 应用——ARP代理
- P1142 轰炸
- HDU_6098 Inversion 【暴力】
- 带参-数组-修改客户姓名
- Error:Configuration with name 'default' not found.
- jsp简介【笔记】
- Oracle问题集锦【不断更新】
- NYOJ 35 表达式求值