【C_socket】select检测键盘输入实现自由聊天
title: 【C_socket】select检测键盘输入实现自由聊天
sticky: 3
top_img:
keywords: “C,socket”
cover:
description:
abbrlink: 46be9372
copyright_author: 秦政
copyright_author_href: https://qinzheng7575.github.io/
copyright_url: https://qinzheng7575.github.io/
copyright_info: 此文章版权归秦政所有,如有转载,请注明來自原作者
typora-copy-images-to: …\Desktop\MD_note\images
文章目录
- 前言
- 目标与关键技术
- select()
- Linux一切皆文件
- 套接字队列
- 非阻塞
- 代码解析
本人博客 https://qinzheng7575.github.io/
前言
在之前写的socket通信程序中,有一个服务器,一接收到消息就会回复一个ACK;有一个客户机,一直等待输入按下回车就可发送。这似乎已经很完美了,能够实现通信,但是,稍微想想它和我们日常使用的聊天程序QQ、微信之间的区别,就能够发现,哦,原来完全没法做到真正的“自由聊天”。
目标与关键技术
- 编写两对简单的一对一聊天程序,分别为面向连接方式和无连接方式
- 双方可以自由聊天,即随时都可以输入或显示对方的数据
要实现第二个,看起来很简单,其实需要引入全新的机制:多路复用机制
我们能不能不用非得等到对面回复了东西才能继续发?能不能在scanf
阻塞等待输入的时候,我先接收对面的东西?要想避免线性流水线式的程序模型,就必须引入多路复用,而select
机制,就是时分复用实现多路复用的形式。
select()
功能:检查多个套接字状态,将其放在对应的队列中,我们就可以根据不同的队列来进行操作了
意味着:每次只要是队列里的socket,就必定代表它发生了某种事情,导致了它在这个队列里面,那么我们接下来的操作肯定可以的
Linux一切皆文件
在Linux中,可以看到明显的编程风格区别,socket套接字不再是由SOCKET定义,而是int,其实就是因为,在操作系统看来一切都是文件,socket也不过是一个可以读、写等操作的文件描述符罢了。
同时,这也意味着,我们就可以直接把文件描述符0,1,2(标准输入、输出、错误),放到select()
中,让输入文字也能够和接收socket消息并行了!
套接字队列
我们在select()
中,需要填三个队列,分别为read_fds
、write_fds
、except_fds
。对套接字队列的操作,有初始化,插入,删除,查找,遍历等。而select()
实际生就是帮我们把各个socket文件描述符,放到其该存在的位置,比如处于accpet
后的套接字,一旦对方send
了东西,那么它就变得可读了,经过select()
后也就被放在了read_fds
队列中。
当然,我们还需要手动创建一个套接字管理队列:因为套接字可能被从套接字队列中删除,需要一个班级的花名册来记录,方便下次再放进套接字队列中。
非阻塞
select我们要开启非阻塞模式,否则它就会阻塞掉,使得没法输入文字了,并且需要设置超时时间,避免忙等消耗掉计算机资源。
代码解析
完整代码请看本人的Github https://github.com/Qinzheng7575
#define STDIN 0//键盘输入文件描述符
struct socket_list {//套接字管理队列结构int MainSock;int num;int socket_array[256];
};
int main(){int s, sock;//int instead SOCKET in Linuxstruct sockaddr_in ser_addr, remote;unsigned int len;char buf[128];struct socket_list sock_list;//我们建立的socket管理列表fd_set readfds, writefds, exceptfds;//三种socket列表,对应读、写、意外int i;unsigned long arg;struct timeval timeout;int retval;//承接select、recv等函数的返回值s = socket(AF_INET, SOCK_DGRAM, 0);//UDPser_addr.sin_family = AF_INET;ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);ser_addr.sin_port = htons(0x1234);bind(s, (struct sockaddr*)&ser_addr, sizeof(ser_addr));remote.sin_family = AF_INET;remote.sin_addr.s_addr = htonl(INADDR_LOOPBACK);remote.sin_port = htons(0x4321);timeout.tv_sec = 2;timeout.tv_usec = 0;init_list(&sock_list);FD_ZERO(&readfds);FD_ZERO(&writefds);FD_ZERO(&exceptfds);arg = 1;int fd = STDIN;//ioctlsocket(sock_list.MainSock, FIONBIO, &arg);//开启非阻塞for winioctl(s, FIONBIO, &arg);//开启非阻塞for linuxioctl(fd, FIONBIO, &arg);while (1) {//建立那三个状态队列FD_ZERO(&readfds);insert_list(s, &sock_list);//it's important!!make_fdlist(&sock_list, &readfds);make_fdlist(&sock_list, &writefds);make_fdlist(&sock_list, &exceptfds);FD_SET(fd, &readfds);retval = select(1024, &readfds, &writefds, &exceptfds, &timeout);//printf("%d\n",retval);//从套接字上的各种事件处理//注意此处应设计为不断从套接字管理队列中逐个取出sock的循环模式for (i = 0; i < 64; i++) {if (sock_list.socket_array[i] == 0)continue;sock = sock_list.socket_array[i];//printf("%d,%d\n",i,sock);//此时已经进入到套接字管理流程了,不需要再管新来的啥的了if (FD_ISSET(STDIN, &readfds)) {char in_buf[128];read(STDIN, in_buf, 127);len = sizeof(remote);int a;//a=sendto(s, "ACK", 3, 0, (sockaddr*)&remote, len);if (strlen(in_buf) > 0) {printf("have read from keyboard:%s\n", in_buf);a = sendto(s, in_buf, strlen(in_buf), 0, (sockaddr*)&remote, len);memset(in_buf, 0x00, sizeof(char) * 128);printf("send ok %d\n", a);}}if (FD_ISSET(sock, &readfds)) {//len = sizeof(sock);len = sizeof(remote);int postion = 0;postion = recvfrom(s, buf, 127, 0, (struct sockaddr*)&remote, &len);buf[postion] = '\0';if (strlen(buf) > 0) {printf("接收到:%s\n", buf);memset(buf, 0x00, sizeof(char) * 128);//sendto(s, "ACK", 3, 0, (sockaddr*)&remote, len);}}if (FD_ISSET(sock, &writefds)) {}if (FD_ISSET(sock, &exceptfds)) {}}}FD_ZERO(&readfds);FD_ZERO(&writefds);FD_ZERO(&exceptfds);close(s);return 0;
}
最后实现的,就是两个terminal能够自由的相对方发送数据,进行聊天!
通过测试界面我们可以看到,在一段打字的时候,并不会影响其接受数据,同时也能够任意发连续的文字,实现自由通信。
【C_socket】select检测键盘输入实现自由聊天相关推荐
- 无阻塞实时检测键盘输入
本人小白一枚,第一次写博客,个位大佬多多指教. 之前一直使用opencv,里面的waitkey函数对于实时检测键盘输入还是比较友好.但是最近只用c++开发之后发现不会怎么实现无阻塞读取键盘输入.查资料 ...
- update与fixedupdate检测键盘输入的出现的问题
先看看二者的区别 unity默认设置中,fixedupdate调用频率为50,在这个情况下,它的调用次数一般是比update要高的. 同:当MonoBehaviour启用时,其在每一帧被调用.都是用来 ...
- python检测键盘输入termios、等待按键超时检测
试了很多方案都不行或者不好用.win10+linux可以用的方法有pygame和termios pygame方法参考:https://blog.csdn.net/qxqxqzzz/article/de ...
- OnKeyPress事件和Javascript检测键盘输入
对于有些时候,我们需要检测用户键盘输入的键盘信息,来处理一些相应的事件. 这里田子建议使用OnKeyPress=""事件来处理.相类似的还有OnKeyUp和OnKeyDown事件, ...
- python检测键盘输入_python实时检测键盘输入函数的示例
在嵌入式.尤其是机器人的python编程中,经常需要实时检测用户的键盘输入来随时控制机器人,这段代码可以帮助我们提取用户输入的字符,并在按下键盘的时候作出反应. import sys import t ...
- c语言检测四个方向键盘输入,如何既检测鼠标单击又检测键盘输入
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 判断鼠标单击程序 COORD pt; int ismouse() { DWORD dwMode, dwOldMode; /* 原来的模式与新模式 */ D ...
- C++ 监视检测键盘输入 字符 并打印
直接上代码: 注意以下代码基于linux系统,注意修改头文件如用windows的话. sublime编译器很方便. 方式一: 可检测多个输入字符,enter结束 #include <fstrea ...
- 【Java入门】--键盘输入月份,控制台返回对应英文月份。
注:本文为入门级编程,大佬留情,如有问题请告知,谢谢. 代码需求: 使用数组,保存12个月的英文单词,从键盘输入对应月份,然后在控制台打印输出对应英文单词. 月份对应单词: 1月-January.2月 ...
- Pygame 键盘输入
4.Pygame 键盘输入 所有的游戏都需要玩家与它进行互动体验.这种体验的第一步是获取用户的输入,并使用此输入以来影响游戏世界. 这方面的常见示例是用于移动角色的箭头键.用于各种攻击 (RPG) 的 ...
最新文章
- 华为系列交换机日志服务器的搭建
- 第二周 数据分析之展示 Matplotlib基础绘图函数实例
- 安卓进阶系列-03上弹选择框(PopupDialog)的使用
- python tkinter教程 博客园_python tkinter教程-事件绑定
- 【ST表】栈(jzoj 2295)
- idea使用junit测试_在JUnit测试中使用Builder模式
- 安卓逆向_20 --- 模拟器检测、反调试检测、ELF动态调试、__libc_init 下断
- openssh升级之后git账户免密登陆失效
- Kinect 开发 —— 近距离探测
- antd vue 位置变动 固钉消失_使用vue封装固钉Affix组件,滚动条到底部时自动吸附,离开底部时自动相对窗口固定...
- 锐起无盘服务器蓝屏死机,正确配置减少锐起无盘系统死机蓝屏
- namp 端口扫描技术
- 以太坊平台评估 私有链和联盟链的机会与挑战
- Word控件Spire.Doc 转换教程(三):如何将 Word 转换为 PDF
- 计算机桌面图片打不开显示内存不足,windows照片查看器无法显示此图片,因为计算机上的可用内存可能不足解决方法...
- 图片从服务器在网页显示,spring从服务器磁盘读取图片,然后显示于前端页面上...
- 外服游戏服务器如何显示中文,避免国外服务器出现乱码的办法
- mysql 保存表情包
- Android 恢复出厂设置上层流程
- 基于Vue+SpringCloudAlibaba微服务电商项目实战-商品服务-015:亿万级别商品详情页面实现动态优化
热门文章
- c语言 二月份天数,C语言选择结构
-C语言计算某月的天数(附带源码)
- 五一期间最受欢迎的几个景区【有图有真相】
- MySQL创建数据表时设定引擎MyISAM/InnoDB
- SAP: SD - 07 Billing
- 热敏电阻PT100,NTC转0-10V/4-20mA转换器
- python定时器 循环_Python系列之循环定时器
- c语言70除以10大于二怎么表示,科目2规则
- jquery-table2excel,进行导出excel
- wait, notify 和 notifyAll区别
- Python中的6个三维可视化工具!