相关函数:

服务端:

socket()

bind()

listen()

FD_ZERO()等辅助函数

select() 高并发select模式

accept()

read() 或 recv()等

write() 或 send()等

close()

客户端:

socket()

connect()

write() 或 send()等

read() 或 recv()等

close()

着重说明下select函数及辅助函数用法说明。

调用select()函数之后,select()函数会清空它所检测的socket描述符集合,所以每次调用select()之前都必须把socket描述符重新加入到待检测的集合中。

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

-nfds: 监听的最大文件描述符值+1

-readfds: 监听socket可读事件的集合的指针 (经常用到的)

-writefds: 监听socket可写事件的集合的指针

-execptfds:监听socket异常事件的集合的指针

-timeout: 设置select监听的超时时间,NULL表示阻塞监听,0表示不阻塞立即返回,>0表示阻塞等待timeout时长

处理三个集合fd_set(实质是位图)的辅助函数:

void FD_CLR(int fd, fd_set *set);//清除集合set中指定fd的位

int FD_ISSET(int fd, fd_set *set);//判断set中指定fd的位是否为真(也就是fd是否在集合set中)

void FD_SET(int fd, fd_set *set);//设置集合set中指定fd的位

void FD_ZERO(fd_set *set);//清空集合set

注意:每当服务端连接断开后,进入TIME_WAIT状态,等待2msl时间之后才能重新使用IP和端口,否则在bind时就会报错。要解决这个问题可以在程序开始时调用端口复用函数setsockopt。原型如下:

//int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

/* sockfd:标识一个套接口的描述字。

   level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。

   optname:需设置的选项。

   optval:指针,指向存放选项值的缓冲区

   optlen:optval缓冲区长度。

   返回值: 成功返回0,失败返回 -1. */

实际调用:

setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

废话不多说,上源码!

实现的功能:客户端C向服务端S发送一串字符数据,S端会对字符串做转大写操作然后回发给C端。直接在咱们Tcp_Server.cpp基础上修改代码

服务端Select_Server.cpp

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include //select() 头文件

#define MAXSIZE 1024

#define IP_ADDR "127.0.0.1"

#define IP_PORT 8888

int main()

{

int i_listenfd, i_connfd;

struct sockaddr_in st_sersock;

char msg[MAXSIZE];

int nrecvSize = 0;

int maxfd = -1;//记录最大fd

fd_set readfds;

int allfds[MAXSIZE];//存放当前所有可用的fd的数组

int index = 0;//记录fd数组中最大fd对应的下标

for(i : allfds)

{

i = -1;

}

if((i_listenfd = socket(AF_INET, SOCK_STREAM, 0) ) < 0)//建立socket套接字

{

printf("socket Error: %s (errno: %d)", strerror(errno), errno);

exit(0);

}

memset(&st_sersock, 0, sizeof(st_sersock));

st_sersock.sin_family = AF_INET; //IPv4协议

st_sersock.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的所有IP,因为有些机子不止一块网卡,多网卡的情况下,这个就表示所有网卡ip地址的意思。

st_sersock.sin_port = htons(IP_PORT);

if(bind(i_listenfd,(struct sockaddr*)&st_sersock, sizeof(st_sersock)) < 0) //将套接字绑定IP和端口用于监听

{

printf("bind Error: %s (errno: %d)", strerror(errno), errno);

exit(0);

}

if(listen(i_listenfd, 20) < 0)//设定可同时排队的客户端最大连接个数

{

printf("listen Error: %s (errno: %d)", strerror(errno), errno);

exit(0);

}

allfds[index] = maxfd = i_listenfd;//先赋值

printf("======waiting for client's request======");

//准备接受客户端连接

while(1)

{

FD_ZERO(&readfds);

for(int i = 0; i<= index; i++)

{

FD_SET(allfds[i], &readfds);//加入可读事件集合中

printf("----------allfds中的元素allfds[%d]:%d", i, allfds[i]);

}

int nCount = select(maxfd+1, &readfds, NULL, NULL, NULL);//select,返回共监听到有多少个fd上有事件

printf("----------select监听到可读事件计数:%d",nCount);

for(int i = 0; i < MAXSIZE; i++)

{

if(nCount == 0)

{

break;

}

if(!FD_ISSET(allfds[i], &readfds))

{

continue;//不在监听事件中则跳过

}

printf("----------即将处理监听到的 allfds[%d]: %d", i, allfds[i]);

if(allfds[i] == i_listenfd)//监听到有客户端连接

{

nCount--;

if((i_connfd = accept(i_listenfd, (struct sockaddr*)NULL, NULL)) < 0)//阻塞等待客户端连接

{

printf("accept Error: %s (errno: %d)", strerror(errno), errno);

//continue;

}

else

{

printf("Client[%d], welcome!", i_connfd);

}

for(int n = 0; n < MAXSIZE; n++)

{

if(allfds[n] == -1)//将新客户端fd加入数组中

{

allfds[n] = i_connfd;

maxfd < i_connfd ? maxfd = i_connfd : true ;

index < n ? index = n : true ;

printf("将新客户端fd加入数组中. fd:%d, maxfd:%d, index:%d", allfds[n], maxfd, index);

break;

}

}

}

else//监听到已连接的客户端发来的数据

{

nCount--;

//接受客户端发来的消息并作处理(小写转大写)后回写给客户端

memset(msg, 0 ,sizeof(msg));

if((nrecvSize = read(allfds[i], msg, MAXSIZE)) < 0)

{

printf("accept Error: %s (errno: %d)", strerror(errno), errno);

continue;

}

else if( nrecvSize == 0)//read返回0代表对方已close断开连接。

{

printf("client has disconnected!");

if(maxfd == allfds[i])

{

maxfd--;

}

if(index == i)

{

index--;

}

close(allfds[i]); //

FD_CLR(allfds[i], &readfds);//清除readfds中对它的监听事件

allfds[i] = -1;//清除数组中相应位置

continue;

}

else

{

printf("recvMsg:%s", msg);

for(int i=0; msg[i] != '0'; i++)

{

msg[i] = toupper(msg[i]);

}

if(write(allfds[i], msg, strlen(msg)+1) < 0)

{

printf("accept Error: %s (errno: %d)", strerror(errno), errno);

}

}

}

}

}//while

close(i_listenfd);

return 0;

}

客户端Select_Client.cpp (直接用咱们Tcp_Client.cpp就可以)

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define MAXSIZE 1024

#define IP_ADDR "127.0.0.1"

#define IP_PORT 8888

int i_sockfd = -1;

void SigCatch(int sigNum)//信号捕捉函数(捕获Ctrl+C)

{

if(i_sockfd != -1)

{

close(i_sockfd);

}

printf("Bye~! Will Exit...");

exit(0);

}

int main()

{

struct sockaddr_in st_clnsock;

char msg[1024];

int nrecvSize = 0;

signal(SIGINT, SigCatch);//注册信号捕获函数

if((i_sockfd = socket(AF_INET, SOCK_STREAM, 0) ) < 0)//建立套接字

{

printf("socket Error: %s (errno: %d)", strerror(errno), errno);

exit(0);

}

memset(&st_clnsock, 0, sizeof(st_clnsock));

st_clnsock.sin_family = AF_INET; //IPv4协议

//IP地址转换(直接可以从物理字节序的点分十进制 转换成网络字节序)

if(inet_pton(AF_INET, IP_ADDR, &st_clnsock.sin_addr) <= 0)

{

printf("inet_pton Error: %s (errno: %d)", strerror(errno), errno);

exit(0);

}

st_clnsock.sin_port = htons(IP_PORT);//端口转换(物理字节序到网络字节序)

if(connect(i_sockfd, (struct sockaddr*)&st_clnsock, sizeof(st_clnsock)) < 0)//主动向设置的IP和端口号的服务端发出连接

{

printf("connect Error: %s (errno: %d)", strerror(errno), errno);

exit(0);

}

printf("======connect to server, sent data======");

while(1)//循环输入,向服务端发送数据并接受服务端返回的数据

{

fgets(msg, MAXSIZE, stdin);

printf("will send: %s", msg);

if(write(i_sockfd, msg, MAXSIZE) < 0)//发送数据

{

printf("write Error: %s (errno: %d)", strerror(errno), errno);

exit(0);

}

memset(msg, 0, sizeof(msg));

if((nrecvSize = read(i_sockfd, msg, MAXSIZE)) < 0)//接受数据

{

printf("read Error: %s (errno: %d)", strerror(errno), errno);

}

else if(nrecvSize == 0)

{

printf("Service Close!");

}

else

{

printf("Server return: %s", msg);

}

}

return 0;

}

js监听select值变化_网络编程——C++实现socket通信(TCP)高并发之select模式相关推荐

  1. 实时监听输入框值变化的完美方案:oninput onpropertychange

    实时监听输入框值变化的完美方案:oninput & onpropertychange 原文:实时监听输入框值变化的完美方案:oninput & onpropertychange 在 W ...

  2. jquery实时监听输入框值变化

    在做web开发时候很多时候都需要即时监听输入框值的变化,以便作出即时动作去引导浏览者增强网站的用户体验感.而采用onchange时间又往往是在输入框失去焦点(onblur)时候触发,有时候并不能满足条 ...

  3. onchange监听input值变化及input隐藏后change事件不触发的原因与解决方法

    1. onchange事件监听input值变化的使用方法: <input id="test"></input>$("input").ch ...

  4. onchange监听input值变化及input隐藏后change事件不触发的原因与解决方法(设置readonly后onchange不起作用的解决方案)...

    转自:https://www.cnblogs.com/white0710/p/7338456.html 1. onchange事件监听input值变化的使用方法: <input id=" ...

  5. onchange监听input值变化及input隐藏后change事件不触发的原因与解决方法(设置readonly后onchange不起作用的解决方案)

    onchange监听input值变化及input隐藏后change事件不触发的原因与解决方法(设置readonly后onchange不起作用的解决方案) 参考文章: (1)onchange监听inpu ...

  6. vue 监听map数组变化_解决vue无法侦听数组及对象属性的变化问题

    一.数组 1.可以监听到的情况 如push.splice.=赋值(array=[1,2,3]) 2.无法监听到的情况 使用下标修改某个元素(这种比较常见) array[index] = 1 objec ...

  7. js 监听URL地址变化

    js 监听URL的hash变化 项目中使用AntdUI组件+react  里面使用了menu组件管理目录结构,不同目录组件页面之中有点击按钮进行不同目录的跳转,因为是各种组件的关系,点击各组件后准确跳 ...

  8. 原生js监听input值发生变化

    原生JS中可以使用oninput,onpropertychange,onchange oninput,onpropertychange,onchange的用法 1) onchange 触发事件必须满足 ...

  9. 父页面监听iframe路由变化_前端路由原理

    对于前端路由应该都很熟悉了,开发过spa应用的应该都用过,只是很少人去查一下前端路由实现的原理. 前端路由的实现核心问题有两个,一个是改变url不刷新,另一个是监听url变化.主要靠的就是hash和h ...

最新文章

  1. git stage 暂存_Git撤销暂存区stage中的内容
  2. python 使用socks5 设置全局代理
  3. 【ubuntu perf安装】The program 'perf' is currently not installed.
  4. 文件或目录权限chmod,更改所有者和所属组chown ,umask的使用 ,隐藏权限的使用 lsattr,chattr...
  5. An ffmpeg and SDL Tutorial
  6. 2019年Linux与开源如何统治技术圈
  7. pandas学习笔记三之处理丢失数据
  8. opt eclipse jre bin java_在Eclipse中指定JDK
  9. Java Servlet
  10. 手把手打造开源新监控利器check_mk
  11. [转载] 使用 Python 实现鼠标键盘自动化
  12. 家庭财务管理系统的设计与实现(Java毕业设计-Springboot)
  13. 【易语言】微信跳一跳教程详细版,分分钟让新手学会的教程(附源码)
  14. python简单速成,一行代码写爬虫
  15. 2022-06-23 JVM学习
  16. 目前比较流行的网站设计风格有哪些
  17. Firefox配置阿里云DNS方法
  18. 2021中国数字经济发展白皮书 附下载
  19. Kafka扩分区和分区副本重分配之后消费组会自动均衡吗?
  20. 独立经济体——投机者的游戏

热门文章

  1. 计算机基础1模拟题,计算机基础模拟题1(有答案).doc
  2. 【Sql server: T-Sql 技术内幕 系列】之索引篇
  3. 机构:去年购房者平均年龄近30岁
  4. 【刷算法】两个链表的第一个公共结点
  5. 实现基于注解(Annotation)的数据库框架(三)自定义注解(Annotation)
  6. kvm 网络配置之nat、用户模式
  7. linux 小白启航之路-搭建linuxDHCP中继服务器
  8. Vue 过渡实现轮播图
  9. Android 插件化总结
  10. iOS利用通知(NSNotification)进行传值