select版的TCP通信

2023-05-16

        编写代码之前,大概先说一下利用select编写tcp的思路及select特点。

        select系统调用是用来让程序监视多个文件句柄的状态变化的,程序会停在select这里等待,直到被监视的句柄有一个或者多个发生了状态改变。

select函数为:int select(int nfds,fd_set *readfds,fd_set* writefds,异常文件描述符,时间长度)//默认时间长度异常事件描述符一般都为NULL

在select中提出四个宏来处理描述数组的方式:(fd为文件描述符集set为描述数组)

FD_SET(fd,fd_set* set):用来设置set中fd位

FD_ISSET(fd,fd_set* set):用来测试set中额相关fd位是否为真

FD_ZERO(fd,fd_set* set):用来清除set的全部位

FD_CLR(fd_set*set):用来清除set中相关的fd的位

当然select的模型最终的特点如下:(1)select下可监控的文件描述符的个数取决于系统的大小

(2)每次检测到一个新的fd,都要手动的将fd添加到set中,并且使用一个数据结构arrar来保存select监控集中的set

(3)select模型必须在设了select前循环array


在大致了解了select的特点之后,现在就来说一说select 版的tcp的编写思路:

1:搭建好基本的tcp的框架,在服务器端编写-->生成套接字(starup),绑定端口(bind),监听(listen)模块,接受客户端访问(accept)模块

2.客户端实现连接请求模块(connect)

3.定义一个数组arrary,初始值为-1,然后把步骤1 中生成的监听套接字(listen_sock)添加到该数组

4.编写select函数监听来自客户端的请求,若监听到客户端连接,就会生成一个new_sock套接字,那么当然把这个套接字添加到数组arrary中。当下次遍历数组时得到的是new_sock套接字,那它就被作为数据传输套接字进行数据接收。

5.在步骤4的基础上读取客户端放在缓冲区的内容。


好啦!以上大致就是编写思路的说明了,下面贴出代码:

服务器端:server.c

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<unistd.h>
#include<string.h>

#define port 8080
#define MAX_FD_NUM 20
int array_fd[MAX_FD_NUM];//for watch fd

int startup()
{
	int sock=socket(AF_INET,SOCK_STREAM,0);
	if(sock<0)
	{
		perror("socket");
		exit(1);
	}
	struct sockaddr_in local;
	local.sin_family=AF_INET;
	local.sin_port=htons(port);
	local.sin_addr.s_addr=htonl(INADDR_ANY);
	if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
	{
		perror("bind");
		exit(1);
	}
	if(listen(sock,5)<0)
	{
		perror("listen");
		exit(1);
	}
	return sock;
}
int main()
{
	int listen_sock=startup();

	struct sockaddr_in client;
        socklen_t len =sizeof(client);

	fd_set read_set;//READ 
	int max_fd=listen_sock;

	//init array
	int i=0;
	for(;i<MAX_FD_NUM;i++)
	{
	     array_fd[i]=-1;//set init key=-1
	}
	array_fd[0]=listen_sock;
	while(1)
	{
	  FD_ZERO(&read_set);//empty read_set
          for(i=0;i<MAX_FD_NUM;i++)
         {
           if(array_fd[i]>0)
          {
	      FD_SET(array_fd[i],&read_set);//set array_fd in red_set
              if(max_fd<array_fd[i])
		  {
			  max_fd=array_fd[i];//get max_fd
		  }
	  }
	 }
	  switch(select(max_fd+1,&read_set,NULL,NULL,NULL))
	  {
		case 0://timeout
			printf("timeout...");
			break;
		case -1://error
			perror("select");
                        break;
		default:
			for(i=0;i<MAX_FD_NUM;i++)
			{
				if(array_fd<0)
				{
					continue;
                }
				//new connect
				else if(array_fd[i]==listen_sock && FD_ISSET(array_fd[i],&read_set))
				{
					int new_sock=accept(array_fd[i],(struct sockaddr*)&client,&len);
					if(new_sock<0)
					{
						continue;
					}
					printf("get new connect: %d\n",new_sock);
					for(i=0;i<MAX_FD_NUM;i++)
					{
                                           if(array_fd[i]==-1)
					  {
						  array_fd[i]=new_sock;
						  break;
					  }
					}
					  if(i==MAX_FD_NUM)
					  {
						  close(new_sock);
					  }
				}
				else
				{
					for(i=1;i<MAX_FD_NUM;i++)
					{
						if(array_fd[i]>0 && FD_ISSET(array_fd[i],&read_set))
						{
							char buf[1024];
							memset(buf,'\0',sizeof(buf));
							ssize_t _size=read(array_fd[i],buf,sizeof(buf)-1);
							if(_size<0)
							{		
								printf("read failed");
								close(array_fd[i]);
							}
							else if(_size==0)
							{
								printf("client close...\n");
								close(array_fd[i]);
							}
							else
							{
								printf("client: %s\n",buf);
							}
						}
					}
				}
			}
			break;
	  }
	}

	close(listen_sock);
	return 0;
}

客户端:client.c

#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<errno.h>
int main()
{
   int read_fd=0;
   int write_fd=1;
   int max_fd=0;
   fd_set read_set;
   fd_set write_set;

   int sock=socket(AF_INET,SOCK_STREAM,0);
   if(sock<0)
   {
	   perror("socket");
	   exit(1);
   }
        struct sockaddr_in remote;
	remote.sin_family=AF_INET;
	remote.sin_port=htons(8080);
	remote.sin_addr.s_addr=inet_addr("192.168.198.128");//本机IP

	int new_sock=connect(sock,(struct sockaddr *)&remote,sizeof(remote));
	if(new_sock<0)
	{
		perror("connect");
		exit(1);
	}
	if(sock >read_fd)
	   max_fd=sock;
	else
		max_fd=read_fd;
	 while(1)
	 {
		 FD_ZERO(&read_set);//empty
		 FD_ZERO(&write_set);
		 FD_SET(read_fd,&read_set);//set
		 FD_SET(sock,&write_set);//

		 switch(select(max_fd+1,&read_set,&write_set,NULL,NULL))
		 {
			 case 0://timeout	
			 printf("timeout...\n");
				 break;
			case -1://error
			 printf("there are bug\n");
			 printf("error...\n");
				 break;
			default://data ready
				 {
				 if(FD_ISSET(read_fd,&read_set))//judge
				 {
					 char buf[1024];
						 ssize_t _size=read(read_fd,buf,sizeof(buf)-1);
						 if(_size>0)
						 {
						 buf[_size]='\0';
						 printf("echo:%s\n",buf);
						 }
				    	 if(FD_ISSET(sock,&write_set))
					     {
							 //printf("write successful\n");
						  send(sock,buf,strlen(buf),0);
                       // printf("%d\n",_size);
						 }
				
					 }
				 }
				 break;
		 }
	 }
	return 0;
}

Makefie文件:

.PHONY:all
all:server client
client:client.c
	gcc -o $@ $^
server:server.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -r server client



















本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

select版的TCP通信 的相关文章

  • 网络服务发现不是发现服务类型

    我想通过 Android 设备在本地网络中找到服务器 我可以通过使用找到它NSDManager具有服务器服务类型的服务 例如 workstation tcp是服务类型 在我的本地网络中我有一个 无线路由器和无线中继器 两者都有不同的SSID
  • 立即检测客户端与服务器套接字的断开连接

    如何检测客户端已与服务器断开连接 我的代码中有以下代码AcceptCallBack method static Socket handler null public static void AcceptCallback IAsyncResu
  • SQL Server 转换选择一列并将其转换为字符串

    是否可以编写一条从表中选择列并将结果转换为字符串的语句 理想情况下 我希望有逗号分隔的值 例如 假设 SELECT 语句看起来像这样 SELECT column FROM table WHERE column lt 10 结果是一列包含值的
  • 使用 jQuery 按标题选择 div

    我有一个带有 div 的网页 其中包含其他几个没有关联 ID 的 div div div title jhon style width 8px height 9px div div title carl style width 8px he
  • 基于两个数据库表之间的数据比较创建oracle视图

    我有下表 我想创建视图以便descr O 以及对于常见的id isin两个表中的字段值 检查ratio字段并只取其中的行ratio字段值低 for descr O 如果 id isin 存在于一个表中但不存在于另一个表中 则获取这些行 双向
  • Dplyr select_ 和starts_with 对变量列表中的多个值进行选择

    我正在从不同位置的不同传感器收集数据 数据输出类似于 df lt data frame date c 2011 2012 2013 2014 2015 Sensor1 Temp c 15 18 15 14 19 Sensor1 Pressu
  • NodeJS:TCP套接字服务器仅在第一次返回数据

    我正在尝试在 node js 中编写一个小型中继脚本 用于侦听本地套接字上传入的 TCP 连接 当它收到连接时 将流量转发给第三方 它还必须从该第三方获取任何返回的数据并将其发送回原始本地套接字 我试过类似的代码http delog wor
  • 使用 select_ 和starts_with R

    为什么这段代码不起作用 mtcars gt select starts with d Error in eval expr envir enclos could not find function starts with 这是简化的示例 我
  • ConnectionTimeout 与 SocketTimeout

    我正在使用的库有问题 可能是图书馆的问题 也可能是我用错了 基本上 当我这样做时 超时以毫秒为单位 ignitedHttp setConnectionTimeout 1 v short ignitedHttp setSocketTimeou
  • SQL SELECT 对值求和,不包括重复项

    我在 Oracle SQL 中遇到一个问题 我正在尝试解决这个问题 我将用一个例子来说明 我正在查询三个表 Employees EmployeeID Name 1 John Smith 2 Douglas Hoppalot 3 Harry
  • SO_REUSEPORT 可以在 Unix 域套接字上使用吗?

    Linux 内核 gt 3 9 允许通过设置在内核负载平衡的进程之间共享套接字SO REUSEPORT http lwn net Articles 542629 http lwn net Articles 542629 这如何用于类型的套接
  • 使用 TcpClient 通过 C# 通过 TCP 发送多个文件

    我正在尝试使用 C TcpClient 通过 TCP 发送多个文件 对于单个文件来说它效果很好 但是当我有多个文件时 它只发送第一个文件 这是我的代码 发送文件 try TcpClient tcpClient new TcpClient N
  • python - select.select() 如何工作?

    背景 我对C很熟悉select 功能 我已经将这个功能用于多种目的 其中大多数 如果不是全部 用于读取和写入管道 文件等 我必须说我从未使用过错误列表 但这不涉及关键问题 问题 有Python的吗select 行为如下 对我来说事实证明se
  • TCP 校验和可能无法检测到错误吗?如果是的话,这件事是如何处理的?

    如果 TCP 有效负载在传输过程中被损坏 则重新计算的校验和将与传输的校验和不匹配 太好了 到目前为止一切都很好 如果 TCP 校验和在传输过程中损坏 则重新计算的校验和将与现在损坏的校验和不匹配 太好了 到目前为止一切都很好 当有效负载和
  • Jmeter TCP Sampler - 如何重用线程之间的连接?

    我在 JMeter 的 ThreadGroup 下设置了一个 TCP 采样器 数据是从 CSV 文件中选取的 第一行数据用于认证 后续行为实际参数数据 像下面这样的东西 AAAAAAA21 BBBBBBBCCCCCCCDDDDDDD BBB
  • 多个客户端如何同时连接到服务器上的一个端口(例如 80)? [复制]

    这个问题在这里已经有答案了 我了解端口工作原理的基础知识 但是 我不明白的是多个客户端如何同时连接到端口 80 我知道每个客户端都有一个唯一的 对于他们的机器 端口 服务器是否从可用端口回复客户端 并简单地声明回复来自 80 这是如何运作的
  • 使用 where 进行 select 语句时,HSQLDB 用户缺乏权限或未找到对象错误

    我的数据库使用 SQuirrel SQL 客户端版本 3 5 3 和 HSQLDB 我已经能够为其指定相应的驱动程序 内存中 并创建一个别名 我创建了一个表 CREATE TABLE ENTRY NAME VARCHAR 100 NOT N
  • 在单个 select 语句中多次有条件地求和同一列?

    我有一个表 显示每个月在给定位置的各种类型的部署的员工部署情况 ID Location ID Date NumEmployees DeploymentType ID 例如 一些记录可能是 1 L1 12 2010 7 1 Permanent
  • 检查两个“select”是否相等

    有没有办法检查两个 非平凡的 选择是否等效 最初我希望两个选择之间有形式上的等价 但是答案在证明 sql 查询等价性 https stackoverflow com questions 56895 proving sql query equ
  • iOS Safari Mobile 禁用上一个和下一个选择输入

    上周五我发现了关于此问题的类似问题 但似乎无法再次找到它 如果有人能指出我正确的方向 那就太好了 本质上我在一个页面上有多个选择菜单 第一个在加载时填充 第二个在第一个选择时填充 够简单的 但是 在 iOS 设备中 当您点击选择元素时 它会

随机推荐

  • spdlog 封装为 DLL

    项目中需要快速写入巨量日志 xff0c 一开始用的是boost log xff0c 但遇到崩溃问题 xff0c 程序负载大了 xff0c 滚动日志时偶尔会崩溃 xff0c 总是报 xff1a boost filesystem error x
  • 驼峰命名法与下划线命名法之争

    窃以为 xff0c 驼峰命名开发效率更高 xff0c 原因如下 xff1a 下划线命名多输入一个字符 例如 xff1a set name 对比 setName xff0c 多输入一个下划线字符 xff0c 敲击键盘两次Shift 43 而驼
  • [PyQt] 在QLabel上用drawText实现文字滚动

    span class token keyword from span PyQt4 span class token punctuation span QtGui span class token keyword import span sp
  • [PyQt] PyQt4写的音乐播放器

    实现了 xff1a 播放歌曲 xff1b 上 下一首 xff1b 随机 循环 单曲循环 xff1b 批量添加 删除歌曲 xff1b 打开 存储播放列表 xff08 M3U格式 xff09 xff1b 添加到收藏 xff1b 单行 多行歌词桌
  • [PyQt] 使用.qrc 生成资源文件供程序中使用

    建立 images qrc文件 xff0c 里面保存了资源位置 xff1a span class hljs doctype lt DOCTYPE RCC gt span span class hljs tag lt span class h
  • Tcl/tk实例-工具栏和菜单-图片预览工具

    可以打开并查看图片 xff0c 点击工具栏上 Previous 和 Next 按钮来浏览 前 下 一张 仅仅是一个例子 xff0c 其它按钮和菜单未添加命令 package require Ttk package require Img p
  • Tcl/tk实例—使用tclkit工具将脚本打包成可执行文件(.exe)

    下载 tclkit exe 工具 xff0c 及 sdx kit 文件 复制一份tclkit exe xff0c 命名为tclkit2 exe 假设你的脚本文件为 xff1a app tcl Step1 命令行执行 tclkit exe s
  • C语言将十进制转换成十六进制

    include lt stdio h gt main char arr 50 61 34 34 char p 61 arr int i scanf 34 d 34 amp i 输入一个十进制的数 int result 61 0 while
  • 软件版本中的release,stable,alpha,beta,pre,snapshot

    转自 xff1a https www jianshu com p aefe0453d081 我们在下载软件会遇到诸如release stable alpha beta pre current eval rc snapshot等版本 xff0
  • kylin ubuntu20.04使用记录

    1 配置dns vim etc systemd resolved conf 修改 DNS 61 119 29 29 29 223 5 5 5 多个DNS地址使用空格分隔 2 配置samba sudo vim etc samba smb co
  • linux进程、线程状态 tomcat线程数 并发数查看

    1 linux进程查看 ps aux top USER PID CPU MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0 0 0 0 10368 116 Ss Jan16 4 57 init
  • 字符编码(三) 字节序、bit序、 有效位

    1 字节序 xff1a 一个 xff08 占多字节的 xff09 数据单元的字节顺序 Java中byte没有字节序问题 xff0c 其他都有字节序问题 不必考虑byte内部bit的细节 bit序 xff1a 一个字节内 xff0c bit的
  • STM32:串口发送

    1 main c代码如下 include stm32f10x h nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp Device header include Delay h include OLED
  • 太阳晒进屋里 太刺眼懒得起来关窗帘?做一个光感遥控吧

    在一个智能音响的交流群里 xff0c 有位群友提出了个想法 xff0c 家里太阳晒进屋里每次都要起来拉窗帘 xff0c 有没有什么办法可以让太阳晒进屋就关窗帘 xff0c 没太阳了又打开窗帘能 xff1f 后来这位群友找到我 xff0c 我
  • 用Python爬虫获取NBA球员的生涯数据

    NBA球迷往往对球员的各项数据以及对应的排名很感兴趣 xff0c 而basketball reference com这个网站的数据十分详尽 为方便浏览 xff0c 我在github建了一个项目 xff0c 借助该网站提供的数据来汇总某个球员
  • FreeRTOS 二值信号量

    参考 开发手册 二值信号量 简介 二值信号量通常用于互斥访问或同步 xff0c 二至信号量没有优先级继承 xff0c 更适合用于同步 xff08 任务与任务或任务与中断的同步 xff09 二值信号量其实就是一个只有一个队列项的队列 xff0
  • QGC地面站二次开发 环境搭建过程

    文章目录 将本机文件复制到安装的虚拟机系统中方法一方法二 ubuntu QT 安装过程问题一 xff1a 安装开始的时候 xff0c 显示磁盘容量不足 问题二 xff1a 现需解决 磁盘已成功扩展 您必须从客户机操作系统内部对磁盘重新进行分
  • c++应该怎样学习?c++服务器开发必备知识

    笔者从事软件开发工作5年 针对c 的特性 用途 整理的进阶式学习笔记 从浅入深地总结重点知识 本文旨在为c c 初学者 初中级开发者和意在转型c 服务器研发的同学们 对基础知识和进阶路线进行详细的整理 适合c 初学者 c 中高级开发岗的同学
  • Hadoop 安装与 HDFS 基础实践

    一 环境 xff08 1 xff09 操作系统 xff1a Linux Ubuntu 20 04 xff08 2 xff09 Hadoop 版本 xff1a 3 3 2 xff08 3 xff09 JDK 版本 xff1a 1 8 或者以上
  • select版的TCP通信

    编写代码之前 xff0c 大概先说一下利用select编写tcp的思路及select特点 select系统调用是用来让程序监视多个文件句柄的状态变化的 xff0c 程序会停在select这里等待 xff0c 直到被监视的句柄有一个或者多个发