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_fdswrite_fdsexcept_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检测键盘输入实现自由聊天相关推荐

  1. 无阻塞实时检测键盘输入

    本人小白一枚,第一次写博客,个位大佬多多指教. 之前一直使用opencv,里面的waitkey函数对于实时检测键盘输入还是比较友好.但是最近只用c++开发之后发现不会怎么实现无阻塞读取键盘输入.查资料 ...

  2. update与fixedupdate检测键盘输入的出现的问题

    先看看二者的区别 unity默认设置中,fixedupdate调用频率为50,在这个情况下,它的调用次数一般是比update要高的. 同:当MonoBehaviour启用时,其在每一帧被调用.都是用来 ...

  3. python检测键盘输入termios、等待按键超时检测

    试了很多方案都不行或者不好用.win10+linux可以用的方法有pygame和termios pygame方法参考:https://blog.csdn.net/qxqxqzzz/article/de ...

  4. OnKeyPress事件和Javascript检测键盘输入

    对于有些时候,我们需要检测用户键盘输入的键盘信息,来处理一些相应的事件. 这里田子建议使用OnKeyPress=""事件来处理.相类似的还有OnKeyUp和OnKeyDown事件, ...

  5. python检测键盘输入_python实时检测键盘输入函数的示例

    在嵌入式.尤其是机器人的python编程中,经常需要实时检测用户的键盘输入来随时控制机器人,这段代码可以帮助我们提取用户输入的字符,并在按下键盘的时候作出反应. import sys import t ...

  6. c语言检测四个方向键盘输入,如何既检测鼠标单击又检测键盘输入

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 判断鼠标单击程序 COORD pt; int ismouse() { DWORD dwMode, dwOldMode; /* 原来的模式与新模式 */ D ...

  7. C++ 监视检测键盘输入 字符 并打印

    直接上代码: 注意以下代码基于linux系统,注意修改头文件如用windows的话. sublime编译器很方便. 方式一: 可检测多个输入字符,enter结束 #include <fstrea ...

  8. 【Java入门】--键盘输入月份,控制台返回对应英文月份。

    注:本文为入门级编程,大佬留情,如有问题请告知,谢谢. 代码需求: 使用数组,保存12个月的英文单词,从键盘输入对应月份,然后在控制台打印输出对应英文单词. 月份对应单词: 1月-January.2月 ...

  9. Pygame 键盘输入

    4.Pygame 键盘输入 所有的游戏都需要玩家与它进行互动体验.这种体验的第一步是获取用户的输入,并使用此输入以来影响游戏世界. 这方面的常见示例是用于移动角色的箭头键.用于各种攻击 (RPG) 的 ...

最新文章

  1. 华为系列交换机日志服务器的搭建
  2. 第二周 数据分析之展示 Matplotlib基础绘图函数实例
  3. 安卓进阶系列-03上弹选择框(PopupDialog)的使用
  4. python tkinter教程 博客园_python tkinter教程-事件绑定
  5. 【ST表】栈(jzoj 2295)
  6. idea使用junit测试_在JUnit测试中使用Builder模式
  7. 安卓逆向_20 --- 模拟器检测、反调试检测、ELF动态调试、__libc_init 下断
  8. openssh升级之后git账户免密登陆失效
  9. Kinect 开发 —— 近距离探测
  10. antd vue 位置变动 固钉消失_使用vue封装固钉Affix组件,滚动条到底部时自动吸附,离开底部时自动相对窗口固定...
  11. 锐起无盘服务器蓝屏死机,正确配置减少锐起无盘系统死机蓝屏
  12. namp 端口扫描技术
  13. 以太坊平台评估 私有链和联盟链的机会与挑战
  14. Word控件Spire.Doc 转换教程(三):如何将 Word 转换为 PDF
  15. 计算机桌面图片打不开显示内存不足,windows照片查看器无法显示此图片,因为计算机上的可用内存可能不足解决方法...
  16. 图片从服务器在网页显示,spring从服务器磁盘读取图片,然后显示于前端页面上...
  17. 外服游戏服务器如何显示中文,避免国外服务器出现乱码的办法
  18. mysql 保存表情包
  19. Android 恢复出厂设置上层流程
  20. 基于Vue+SpringCloudAlibaba微服务电商项目实战-商品服务-015:亿万级别商品详情页面实现动态优化

热门文章

  1. c语言 二月份天数,C语言选择结构 -C语言计算某月的天数(附带源码)
  2. 五一期间最受欢迎的几个景区【有图有真相】
  3. MySQL创建数据表时设定引擎MyISAM/InnoDB
  4. SAP: SD - 07 Billing
  5. 热敏电阻PT100,NTC转0-10V/4-20mA转换器
  6. python定时器 循环_Python系列之循环定时器
  7. c语言70除以10大于二怎么表示,科目2规则
  8. jquery-table2excel,进行导出excel
  9. wait, notify 和 notifyAll区别
  10. Python中的6个三维可视化工具!