select监听多个client -- linux函数
使用select函数能够以非堵塞的方式和多个socket通信。程序仅仅是演示select函数的使用,功能很easy,即使某个连接关闭以后也不会改动当前连接数。连接数达到最大值后会终止程序。
1. 程序使用了一个数组fd_A,通信開始后把须要通信的多个socket描写叙述符都放入此数组。
2. 首先生成一个叫sock_fd的socket描写叙述符,用于监听port。
3. 将sock_fd和数组fd_A中不为0的描写叙述符放入select将检查的集合fdsr。
4. 处理fdsr中能够接收数据的连接。假设是sock_fd,表明有新连接增加。将新增加连接的socket描写叙述符放置到fd_A。
这部分代码实现逻辑不错,只是有点bug,对套接字缓存未做处理完整。
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #define MYPORT 1234 // the port users will be connecting to
- #define BACKLOG 5 // how many pending connections queue will hold
- #define BUF_SIZE 200
- int fd_A[BACKLOG]; // accepted connection fd
- int conn_amount; // current connection amount
- void showclient()
- {
- int i;
- printf("client amount: %d\n", conn_amount);
- for (i = 0; i < BACKLOG; i++) {
- printf("[%d]:%d ", i, fd_A[i]);
- }
- printf("\n\n");
- }
- int main(void)
- {
- int sock_fd, new_fd; // listen on sock_fd, new connection on new_fd
- struct sockaddr_in server_addr; // server address information
- struct sockaddr_in client_addr; // connector's address information
- socklen_t sin_size;
- int yes = 1;
- char buf[BUF_SIZE];
- int ret;
- int i;
- if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- perror("socket");
- exit(1);
- }
- if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
- perror("setsockopt");
- exit(1);
- }
- server_addr.sin_family = AF_INET; // host byte order
- server_addr.sin_port = htons(MYPORT); // short, network byte order
- server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
- memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));
- if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
- perror("bind");
- exit(1);
- }
- if (listen(sock_fd, BACKLOG) == -1) {
- perror("listen");
- exit(1);
- }
- printf("listen port %d\n", MYPORT);
- fd_set fdsr;
- int maxsock;
- struct timeval tv;
- conn_amount = 0;
- sin_size = sizeof(client_addr);
- maxsock = sock_fd;
- while (1) {
- // initialize file descriptor set
- FD_ZERO(&fdsr);
- FD_SET(sock_fd, &fdsr);
- // timeout setting
- tv.tv_sec = 30;
- tv.tv_usec = 0;
- // add active connection to fd set
- for (i = 0; i < BACKLOG; i++) {
- if (fd_A[i] != 0) {
- FD_SET(fd_A[i], &fdsr);
- }
- }
- ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);
- if (ret < 0) {
- perror("select");
- break;
- } else if (ret == 0) {
- printf("timeout\n");
- continue;
- }
- // check every fd in the set
- for (i = 0; i < conn_amount; i++) {
- if (FD_ISSET(fd_A[i], &fdsr)) {
- ret = recv(fd_A[i], buf, sizeof(buf), 0);
- if (ret <= 0) { // client close
- printf("client[%d] close\n", i);
- close(fd_A[i]);
- FD_CLR(fd_A[i], &fdsr);
- fd_A[i] = 0;
- } else { // receive data
- if (ret < BUF_SIZE)
- memset(&buf[ret], '\0', 1);
- printf("client[%d] send:%s\n", i, buf);
- }
- }
- }
- // check whether a new connection comes
- if (FD_ISSET(sock_fd, &fdsr)) {
- new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
- if (new_fd <= 0) {
- perror("accept");
- continue;
- }
- // add to fd queue
- if (conn_amount < BACKLOG) {
- fd_A[conn_amount++] = new_fd;
- printf("new connection client[%d] %s:%d\n", conn_amount,
- inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
- if (new_fd > maxsock)
- maxsock = new_fd;
- }
- else {
- printf("max connections arrive, exit\n");
- send(new_fd, "bye", 4, 0);
- close(new_fd);
- break;
- }
- }
- showclient();
- }
- // close other connections
- for (i = 0; i < BACKLOG; i++) {
- if (fd_A[i] != 0) {
- close(fd_A[i]);
- }
- }
- exit(0);
- }
我这里做改动(大概逻辑)
- for(i=0;i<BACKLOG;i++)
- {
- tcpSockIndex[i] = -1;
- }
- while(1)
- {
- FD_ZERO(&readfds);
- FD_SET(tcpSock, &readfds);
- maxfdp = maxfdp>tcpSock?maxfdp:tcpSock;
- for(i=0;i<BACKLOG;i++)
- {
- // AB_LOG("FD_SET tcpSockIndex[%d] = %d.\n", i, tcpSockIndex[i]);
- if(-1 != tcpSockIndex[i])
- {
- FD_SET(tcpSockIndex[i], &readfds);
- maxfdp = maxfdp>tcpSockIndex[i]?
- maxfdp:tcpSockIndex[i];
- }
- }
- timeout.tv_sec = SELECT_TIME_OUT_TM;
- timeout.tv_usec = 0;
- ret = select(maxfdp+1, &readfds, NULL, NULL, &timeout);
- if(ret < 0)
- {
- AB_PERROR("select error!\n");
- return ;
- }
- else if(0 == ret)
- {
- AB_PERROR("select time out!\n");
- }
- //处理client发送的报文
- for(i=0; i<BACKLOG; i++)
- {
- if ( -1 != tcpSockIndex[i] &&
- FD_ISSET(tcpSockIndex[i], &readfds))
- {
- AB_LOG("--- tcp client ---.\n");
- pthread_t pthd2;
- TCP_SOCK_T * pTcpSock = NULL;
- pTcpSock = (TCP_SOCK_T *)malloc(sizeof(TCP_SOCK_T));
- pTcpSock->sock = tcpSockIndex[i];
- pthread_create(&pthd2, NULL, bc_sock_handle_client_data, (void *)pTcpSock);
- #if 0
- bc_sock_handle_client_data(tcpSockIndex[i]);
- ret = read(tcpSockIndex[i], NULL, 0);
- AB_LOG("close tcpSockIndex[%d] = %d, ret = %d.\n", i, tcpSockIndex[i], ret );
- //关闭client连接的套接字
- if(-1 == tcpSockIndex[i]) close(tcpSockIndex[i]);
- #endif
- //清空client字符集
- FD_CLR(tcpSockIndex[i], &readfds);
- tcpSockIndex[i] = -1;
- tcpClientConnNum --;
- }
- }
- //获取client连接过来的套接字
- if(FD_ISSET(tcpSock, &readfds))
- {
- AB_LOG("--- tcp server ---.\n");
- if((tcpSockClient = accept(tcpSock,
- (struct sockaddr*)&chiAddr, &cliLen)) <= 0 )
- {
- AB_PERROR("BCHV accept socket error: %s(errno: %d).\n",strerror(errno), errno);
- continue;
- }
- //在套接字数组中找出一个可用加入的位置。
- for(i=0,tcpSockFlag=0; i<BACKLOG; i++)
- {
- AB_LOG("tcpSockIndex[%d] = %d.\n", i, tcpSockIndex[i]);
- if(-1 == tcpSockIndex[i])
- {
- tcpSockIndex[i] = tcpSockClient;
- tcpClientConnNum ++;
- AB_LOG("new connection client[%d] %08X:%d.\n", tcpClientConnNum,
- chiAddr.sin_addr.s_addr, ntohs(chiAddr.sin_port));
- //错误打印
- //AB_LOG("new connection client[%d] %s.\n", tcpClientConnNum,
- // inet_ntoa(chiAddr.sin_addr));
- #if 0
- if (sock_c > maxfdp)
- maxfdp = sock_c;
- #endif
- tcpSockFlag = 1;
- break;
- }
- }
- //超过最大连接请求。能够发送client断开连接
- if(0 == tcpSockFlag)
- {
- AB_LOG("max connections arrive, exit\n");
- send(tcpSockClient, "bye", 4, 0);
- close(tcpSockClient);
- }
- }
- }
- //关闭全部client套接字
- for(i=0; i<BACKLOG; i++)
- {
- if(-1 != tcpSockIndex[i])
- {
- close(tcpSockIndex[i]);
- }
- }
文章摘自 http://www.cnblogs.com/faraway/archive/2009/03/06/1404449.html
select监听多个client -- linux函数的更多相关文章
- select监听服务端
# can_read, can_write, _ = select.select(inputs, outputs, None, None)## 第一个参数是我们需要监听可读的套接字, 第二个参数是我们 ...
- Hi3559AV100板载开发系列-pthread_create()下V4L2接口MJPEG像素格式的VIDIOC_DQBUF error问题解决-采用阻塞方式下select监听
最近一直加班加点进行基于Hi3559AV100平台的BOXER-8410AI板载开发,在开发的过程中,遇到了相当多的问题,其一是板载的开发资料没有且功能不完整,厂家不提供太多售后技术支持,厂家对部分 ...
- 多个进程对同一个监听套接字调用函数gen_tcp:accept/1
源于<<erlang程序设计>>的第14章的14.1.4大约第197页. 未发现多个进程对同一个监听套接字调用函数gen_tcp:accept/1比单进程的效率更高或者更快.
- select监听udp消息
服务端 #!/usr/bin/python2.6 # -*- coding:utf-8 -*- import json import socket import select def socketse ...
- layui的select监听
首先,select一定要放在<form class="layui-form" ></form>里面 然后,加监听<select id="id ...
- Js事件监听封装(支持匿名函数)
先看demo:http://liutian1937.github.io/demo/EventListen.html/*绑定事件与取消绑定*/ var handleHash = {}; var bind ...
- 实时监听 mysql 操作,Linux 版
效果 场景:某数据库新增了某条记录,服务器可以监听到变化的数据与操作,如 增加一条记录: id = 1009,name=''test,number = 11 服务器监听结果: 实现过程 测试过程:数据 ...
- PostgreSQL服务端监听设置及client连接方法
背景介绍: PostgreSQL服务端执行在RedHat Linux上,IP为:192.168.230.128 client安装在Windows XP上, IP为:192.168.230.1 配置方法 ...
- linux epoll机制对TCP 客户端和服务端的监听C代码通用框架实现
1 TCP简介 tcp是一种基于流的应用层协议,其“可靠的数据传输”实现的原理就是,“拥塞控制”的滑动窗口机制,该机制包含的算法主要有“慢启动”,“拥塞避免”,“快速重传”. 2 TCP socket ...
随机推荐
- LeetCode OJ--Unique Paths II **
https://oj.leetcode.com/problems/unique-paths-ii/ 图的深搜,有障碍物,有的路径不通. 刚开始想的时候用组合数算,但是公式没有推导出来. 于是用了深搜, ...
- Drupal service module 介绍
https://www.ostraining.com/blog/drupal/services/ https://www.drupal.org/node/1246470 https://www.dru ...
- Lucene.net站内搜索-最简单搜索引擎代码
Lucene.Net核心类简介 先运行写好的索引的代码,再向下讲解各个类的作用,不用背代码. (*)Directory表示索引文件(Lucene.net用来保存用户扔过来的数据的地方)保存的地方,是抽 ...
- MX
A mail exchanger record (MX record) is a type of resource record in the Domain Name System that spec ...
- VMware虚拟机直连物理网络的两种方式
VMware虚拟机直连物理网络的两种方式 使用VMware构建虚拟机,通常虚拟机都使用NAT模式.这时,虚拟机有独立的网段.使用NAT模式,虚拟机之间数据都通过虚拟网络传输,不会影响实体机所在的实 ...
- 东方14模拟赛之noip2015/day1/3/神奇的幻方
总时间限制: 10000ms 单个测试点时间限制: 1000ms 内存限制: 128000kB 描述 幻方是一种很神奇的N*N 矩阵:它由数字 1,2,3, … …,N*N 构成,且每行.每列及 ...
- 小W计树
排列组合思想. 先跑一遍最短路, 再从1节点开始搜索, 假如搜到一个点的路径长度等于最短路, 则记录到达该点的路径数 + 1. 最后遍历一遍, ans *= rec[i] 输出答案即可. 关键在于想到 ...
- 【spring mvc】后台的API,测试中,总提示接口实体的某一个字段不能为null,但是明明给值了还提示不能为空
实体是这三个字段 接口的实现类Controller 前台测试给值 依旧报错 解决方法: 需要添加@RequestBody注解
- 6.【nuxt起步】-完成一个静态的页面
1.接下来新建/component/maincontent.vue 把这些html代码copy到maincontent.vue 发现格式比较难看,就格式化一下 2.插件安装 beautify,安装后重 ...
- 文件系统之-JAVA Sftp远程操作:
转载:http://blog.csdn.net/lee272616/article/details/52789018 java远程操作文件服务器(linux),使用sftp协议版本会持续更新,当前版本 ...