opencart做网站视频小程序开发需要多少钱知乎
opencart做网站视频,小程序开发需要多少钱知乎,东莞网站建设设,app是什么公司IO多路复用机制select实现TCP服务器 一、前言二、新增使用API函数2.1、select()函数2.2、FD_*系列函数 三、实现步骤四、完整代码五、TCP客户端5.1、自己实现一个TCP客户端5.2、Windows下可以使用NetAssist的网络助手工具 小结 一、前言
手把手教你从0开始编写TCP服务器程序体验开局一块砖大厦全靠垒。
为了避免篇幅过长使读者感到乏味对【TCP服务器的开发】进行分阶段实现一步步进行优化升级。 本节在上一章节的基础上将并发的实现改为IO多路复用机制使用select管理每个新接入的客户端连接实现发送和接收。
二、新增使用API函数
2.1、select()函数
函数原型
#include sys/types.h
#include unistd.hint select(int maxfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);select函数共有5个参数其中参数
maxfds监视对象文件描述符数量。readset将所有关注“是否存在待读取数据”的文件描述符注册到fd_set变量并传递其地址值。writeset 将所有关注“是否可传输无阻塞数据”的文件描述符注册到fd_set变量并传递其地址值。exceptset将所有关注“是否发生异常”的文件描述符注册到fd_set变量并传递其地址值。timeout调用select后为防止陷入无限阻塞状态传递超时信息。
返回值
错误返回-1。超时返回0。
当关注的事件返回时返回大于0的值该值是发生事件的文件描述符数。
2.2、FD_*系列函数
函数原型
#include sys/types.h
#include unistd.hvoid FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);1FD_CLR函数用于将fd从set集合中清除即不监控该fd的事件。
2FD_SET函数用于将fd添加到set集合中监控其事件。
3FD_ZERO函数用于将set集合重置。
4FD_ISSET函数用于判断set集合中的fd是否有事件读、写、错误。
三、实现步骤
什么是IO多路复用通俗的讲就是一个线程通过记录IO流的状态来管理多个IO。解决创建多个进程处理IO流导致CPU占用率高的问题。
select是io多路复用的一种方式其他的还有poll、epoll等。
1创建socket。
int listenfdsocket(AF_INET,SOCK_STREAM,0);
if(listenfd-1){printf(errno %d, %s\n,errno,strerror(errno));return SOCKET_CREATE_FAILED;
}2绑定地址。
struct sockaddr_in server;
memset(server,0,sizeof(server));server.sin_familyAF_INET;
server.sin_addr.s_addrhtonl(INADDR_ANY);
server.sin_porthtons(LISTEN_PORT);if(-1bind(listenfd,(struct sockaddr*)server,sizeof(server))){printf(errno %d, %s\n,errno,strerror(errno));close(listenfd);return SOCKET_BIND_FAILED;
}3设置监听。
if(-1listen(listenfd,BLOCK_SIZE)){printf(errno %d, %s\n,errno,strerror(errno));close(listenfd);return SOCKET_LISTEN_FAILED;
}4初始化可读文件描述符集合将监听套接字加入集合。
fd_set writefds,readfds,wset,rset;
FD_ZERO(readfds);
FD_ZERO(writefds);
FD_SET(listenfd,readfds);5从可读文件描述符集合中选择一个就绪的套接字。
wsetwritefds;
rsetreadfds;// 从可读文件描述符集合中选择就绪的套接字
int nreadyselect(maxfd1,rset,wset,NULL,NULL);if(nready-1)
{printf(select errno %d, %s\n,errno,strerror(errno));continue;
}6如果监听套接字有新连接请求处理新连接。
struct sockaddr_in client;
memset(client,0,sizeof(client));
socklen_t lensizeof(client);int clientfdaccept(listenfd,(struct sockaddr*)client,len);
if(clientfd-1){printf(accept errno %d, %s\n,errno,strerror(errno));
}
else{printf(accept successdul, clientfd %d\n,clientfd);// 将新套接字加入可读文件描述符集合FD_SET(clientfd,readfds);if(clientfdmaxfd)maxfdclientfd;
}7处理客户端发来的数据和发送数据到客户端。 int i0;for(ilistenfd1;imaxfd;i){if(FD_ISSET(i,rset)){printf(recv fd%d\n,i);retrecv(i,buf,BUFFER_LENGTH,0);if(ret0) {// 客户端断开连接printf(connection dropped\n);// 从可读文件描述符集合中移除该套接字FD_CLR(i,readfds);close(i);}else if(ret0){printf(fd%d recv -- %s\n,i,buf);FD_CLR(i,readfds);FD_SET(i,writefds);}}else if(FD_ISSET(i,wset)){printf(send to fd%d\n,i);retsend(i,buf,ret,0);if(ret-1){printf(send() errno %d, %s\n,errno,strerror(errno));}FD_CLR(i,writefds);FD_SET(i,readfds);}}四、完整代码
#include stdio.h
#include sys/socket.h
#include sys/types.h
#include netinet/in.h#include errno.h
#include string.h
#include unistd.h#include sys/select.h#define LISTEN_PORT 9999
#define BLOCK_SIZE 10
#define BUFFER_LENGTH 1024enum ERROR_CODE{SOCKET_CREATE_FAILED-1,SOCKET_BIND_FAILED-2,SOCKET_LISTEN_FAILED-3,SOCKET_ACCEPT_FAILED-4,SOCKET_SELECT_FAILED-5
};int main(int argc,char **argv)
{// 1.int listenfdsocket(AF_INET,SOCK_STREAM,0);if(listenfd-1){printf(errno %d, %s\n,errno,strerror(errno));return SOCKET_CREATE_FAILED;}// 2.struct sockaddr_in server;memset(server,0,sizeof(server));server.sin_familyAF_INET;server.sin_addr.s_addrhtonl(INADDR_ANY);server.sin_porthtons(LISTEN_PORT);if(-1bind(listenfd,(struct sockaddr*)server,sizeof(server))){printf(errno %d, %s\n,errno,strerror(errno));close(listenfd);return SOCKET_BIND_FAILED;}// 3.if(-1listen(listenfd,BLOCK_SIZE)){printf(errno %d, %s\n,errno,strerror(errno));close(listenfd);return SOCKET_LISTEN_FAILED;}printf(listen port: %d\n,LISTEN_PORT);fd_set writefds,readfds,wset,rset;FD_ZERO(readfds);FD_ZERO(writefds);FD_SET(listenfd,readfds);char buf[BUFFER_LENGTH]{0};int ret0;int maxfdlistenfd;while(1){wsetwritefds;rsetreadfds;// 从可读文件描述符集合中选择就绪的套接字int nreadyselect(maxfd1,rset,wset,NULL,NULL);if(nready-1){printf(select errno %d, %s\n,errno,strerror(errno));continue;}// 如果监听套接字有新连接请求处理新连接if(FD_ISSET(listenfd,rset)){// 4.printf(accept , listenfd %d\n,listenfd);struct sockaddr_in client;memset(client,0,sizeof(client));socklen_t lensizeof(client);int clientfdaccept(listenfd,(struct sockaddr*)client,len);if(clientfd-1){printf(accept errno %d, %s\n,errno,strerror(errno));}else{printf(accept successdul, clientfd %d\n,clientfd);// 将新套接字加入可读文件描述符集合FD_SET(clientfd,readfds);if(clientfdmaxfd)maxfdclientfd;}}printf(listenfd%d.maxfd%d\n,listenfd,maxfd);int i0;for(ilistenfd1;imaxfd;i){if(FD_ISSET(i,rset)){printf(recv fd%d\n,i);retrecv(i,buf,BUFFER_LENGTH,0);if(ret0) {// 客户端断开连接printf(connection dropped\n);// 从可读文件描述符集合中移除该套接字FD_CLR(i,readfds);close(i);}else if(ret0){printf(fd%d recv -- %s\n,i,buf);FD_CLR(i,readfds);FD_SET(i,writefds);}}else if(FD_ISSET(i,wset)){printf(send to fd%d\n,i);retsend(i,buf,ret,0);if(ret-1){printf(send() errno %d, %s\n,errno,strerror(errno));}FD_CLR(i,writefds);FD_SET(i,readfds);}}}close(listenfd);return 0;
}编译命令
gcc -o server server.c五、TCP客户端
5.1、自己实现一个TCP客户端
自己实现一个TCP客户端连接TCP服务器的代码
#include stdio.h
#include sys/socket.h#include netinet/in.h
#include arpa/inet.h#include errno.h
#include string.h#include unistd.h
#include stdlib.h#define BUFFER_LENGTH 1024enum ERROR_CODE{SOCKET_CREATE_FAILED-1,SOCKET_CONN_FAILED-2,SOCKET_LISTEN_FAILED-3,SOCKET_ACCEPT_FAILED-4
};int main(int argc,char** argv)
{if(argc3){printf(Please enter the server IP and port.);return 0;}printf(connect to %s, port%s\n,argv[1],argv[2]);int connfdsocket(AF_INET,SOCK_STREAM,0);if(connfd-1){printf(errno %d, %s\n,errno,strerror(errno));return SOCKET_CREATE_FAILED;}struct sockaddr_in serv;serv.sin_familyAF_INET;serv.sin_addr.s_addrinet_addr(argv[1]);serv.sin_porthtons(atoi(argv[2]));socklen_t lensizeof(serv);int rwfdconnect(connfd,(struct sockaddr*)serv,len);if(rwfd-1){printf(errno %d, %s\n,errno,strerror(errno));close(rwfd);return SOCKET_CONN_FAILED;}int ret1;while(ret0){char buf[BUFFER_LENGTH]{0};printf(Please enter the string to send:\n);scanf(%s,buf);send(connfd,buf,strlen(buf),0);memset(buf,0,BUFFER_LENGTH);printf(recv:\n);retrecv(connfd,buf,BUFFER_LENGTH,0);printf(%s\n,buf);}close(rwfd);return 0;
}编译
gcc -o client client.c5.2、Windows下可以使用NetAssist的网络助手工具 下载地址http://old.tpyboard.com/downloads/NetAssist.exe
小结
至此我们实现了一个使用IO多路复用机制实现的服务器这时的TCP服务器可以使用一个线程就能处理多个客户端连接。通过记录IO流的状态来管理多个IO解决创建多个进程处理IO流导致CPU占用率高的问题。
我们总结一下select的使用流程
1、定义io管理状态变量fd_set rfds,wfds;
2、初始化变量FD_ZERO();
3、设置io流状态最初只有监听的fd,将其设置FD_SET(listenfd,rfds);
4、在循环中select。
5、FD_ISSET()判断端口是否有连接。
6、FD_ISSET()判断可读、可写状态。
select是io多路复用的一种方式其他的还有poll、epoll等。下一章节我们将使用更高效的IO多路复用器epoll来实现TCP服务器。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/87549.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!