前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Linux网络编程一步一步学-异步通讯聊天程序select

Linux网络编程一步一步学-异步通讯聊天程序select

作者头像
阳光岛主
发布于 2019-02-19 09:55:37
发布于 2019-02-19 09:55:37
8060
举报
文章被收录于专栏:米扑专栏米扑专栏

Linux网络编程一步一步学-异步通讯聊天程序select

Client

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/wait.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/time.h>

#include <sys/types.h>

#define MAXBUF 1024

/************关于本文档********************************************

*filename: async-server.c

*purpose: 演示网络异步通讯,这是服务器端程序

*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)

Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言

*date time:2007-01-25 21:22

*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途

* 但请遵循GPL

*Thanks to: Google.com

*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力

* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!

*********************************************************************/

int main(int argc, char **argv)

{

int sockfd, new_fd;

socklen_t len;

struct sockaddr_in my_addr, their_addr;

unsigned int myport, lisnum;

char buf[MAXBUF + 1];

fd_set rfds;

struct timeval tv;

int retval, maxfd = -1;

if (argv[1])

myport = atoi(argv[1]);

else

myport = 7838;

if (argv[2])

lisnum = atoi(argv[2]);

else

lisnum = 2;

if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {

perror("socket");

exit(1);

}

bzero(&my_addr, sizeof(my_addr));

my_addr.sin_family = PF_INET;

my_addr.sin_port = htons(myport);

if (argv[3])

my_addr.sin_addr.s_addr = inet_addr(argv[3]);

else

my_addr.sin_addr.s_addr = INADDR_ANY;

if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))

== -1) {

perror("bind");

exit(1);

}

if (listen(sockfd, lisnum) == -1) {

perror("listen");

exit(1);

}

while (1) {

printf

("/n----等待新的连接到来开始新一轮聊天……/n");

len = sizeof(struct sockaddr);

if ((new_fd =

accept(sockfd, (struct sockaddr *) &their_addr,

&len)) == -1) {

perror("accept");

exit(errno);

} else

printf("server: got connection from %s, port %d, socket %d/n",

inet_ntoa(their_addr.sin_addr),

ntohs(their_addr.sin_port), new_fd);

/* 开始处理每个新连接上的数据收发 */

printf

("/n准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方/n");

while (1) {

/* 把集合清空 */

FD_ZERO(&rfds);

/* 把标准输入句柄0加入到集合中 */

FD_SET(0, &rfds);

maxfd = 0;

/* 把当前连接句柄new_fd加入到集合中 */

FD_SET(new_fd, &rfds);

if (new_fd > maxfd)

maxfd = new_fd;

/* 设置最大等待时间 */

tv.tv_sec = 1;

tv.tv_usec = 0;

/* 开始等待 */

retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);

if (retval == -1) {

printf("将退出,select出错! %s", strerror(errno));

break;

} else if (retval == 0) {

/* printf

("没有任何消息到来,用户也没有按键,继续等待……/n"); */

continue;

} else {

if (FD_ISSET(0, &rfds)) {

/* 用户按键了,则读取用户输入的内容发送出去 */

bzero(buf, MAXBUF + 1);

fgets(buf, MAXBUF, stdin);

if (!strncasecmp(buf, "quit", 4)) {

printf("自己请求终止聊天!/n");

break;

}

len = send(new_fd, buf, strlen(buf) - 1, 0);

if (len > 0)

printf

("消息:%s/t发送成功,共发送了%d个字节!/n",

buf, len);

else {

printf

("消息'%s'发送失败!错误代码是%d,错误信息是'%s'/n",

buf, errno, strerror(errno));

break;

}

}

if (FD_ISSET(new_fd, &rfds)) {

/* 当前连接的socket上有消息到来则接收对方发过来的消息并显示 */

bzero(buf, MAXBUF + 1);

/* 接收客户端的消息 */

len = recv(new_fd, buf, MAXBUF, 0);

if (len > 0)

printf

("接收消息成功:'%s',共%d个字节的数据/n",

buf, len);

else {

if (len < 0)

printf

("消息接收失败!错误代码是%d,错误信息是'%s'/n",

errno, strerror(errno));

else

printf("对方退出了,聊天终止/n");

break;

}

}

}

}

close(new_fd);

/* 处理每个新连接上的数据收发结束 */

printf("还要和其它连接聊天吗?(no->退出)");

fflush(stdout);

bzero(buf, MAXBUF + 1);

fgets(buf, MAXBUF, stdin);

if (!strncasecmp(buf, "no", 2)) {

printf("终止聊天!/n");

break;

}

}

close(sockfd);

return 0;

}

Server

#include <stdio.h>

#include <string.h>

#include <errno.h>

#include <sys/socket.h>

#include <resolv.h>

#include <stdlib.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <unistd.h>

#include <sys/time.h>

#include <sys/types.h>

#define MAXBUF 1024

/************关于本文档********************************************

// *filename: ssync-client.c

*purpose: 演示网络异步通讯,这是客户端程序

*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)

Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言

*date time:2007-01-25 21:32

*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途

* 但请遵循GPL

*Thanks to: Google.com

*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力

* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!

*********************************************************************/

int main(int argc, char **argv)

{

int sockfd, len;

struct sockaddr_in dest;

char buffer[MAXBUF + 1];

fd_set rfds;

struct timeval tv;

int retval, maxfd = -1;

if (argc != 3) {

printf

("参数格式错误!正确用法如下:/n/t/t%s IP地址 端口/n/t比如:/t%s 127.0.0.1 80/n此程序用来从某个 IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息",

argv[0], argv[0]);

exit(0);

}

/* 创建一个 socket 用于 tcp 通信 */

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

perror("Socket");

exit(errno);

}

/* 初始化服务器端(对方)的地址和端口信息 */

bzero(&dest, sizeof(dest));

dest.sin_family = AF_INET;

dest.sin_port = htons(atoi(argv[2]));

if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) {

perror(argv[1]);

exit(errno);

}

/* 连接服务器 */

if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {

perror("Connect ");

exit(errno);

}

printf

("/n准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方/n");

while (1) {

/* 把集合清空 */

FD_ZERO(&rfds);

/* 把标准输入句柄0加入到集合中 */

FD_SET(0, &rfds);

maxfd = 0;

/* 把当前连接句柄sockfd加入到集合中 */

FD_SET(sockfd, &rfds);

if (sockfd > maxfd)

maxfd = sockfd;

/* 设置最大等待时间 */

tv.tv_sec = 1;

tv.tv_usec = 0;

/* 开始等待 */

retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);

if (retval == -1) {

printf("将退出,select出错! %s", strerror(errno));

break;

} else if (retval == 0) {

/* printf

("没有任何消息到来,用户也没有按键,继续等待……/n"); */

continue;

} else {

if (FD_ISSET(sockfd, &rfds)) {

/* 连接的socket上有消息到来则接收对方发过来的消息并显示 */

bzero(buffer, MAXBUF + 1);

/* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */

len = recv(sockfd, buffer, MAXBUF, 0);

if (len > 0)

printf

("接收消息成功:'%s',共%d个字节的数据/n",

buffer, len);

else {

if (len < 0)

printf

("消息接收失败!错误代码是%d,错误信息是'%s'/n",

errno, strerror(errno));

else

printf("对方退出了,聊天终止!/n");

break;

}

}

if (FD_ISSET(0, &rfds)) {

/* 用户按键了,则读取用户输入的内容发送出去 */

bzero(buffer, MAXBUF + 1);

fgets(buffer, MAXBUF, stdin);

if (!strncasecmp(buffer, "quit", 4)) {

printf("自己请求终止聊天!/n");

break;

}

/* 发消息给服务器 */

len = send(sockfd, buffer, strlen(buffer) - 1, 0);

if (len < 0) {

printf

("消息'%s'发送失败!错误代码是%d,错误信息是'%s'/n",

buffer, errno, strerror(errno));

break;

} else

printf

("消息:%s/t发送成功,共发送了%d个字节!/n",

buffer, len);

}

}

}

/* 关闭连接 */

close(sockfd);

return 0;

}

编译用如下命令: gcc -Wall async-server.c -o server gcc -Wall async-client.c -o client 运行用如下命令: ./server 7838 1 ./client 127.0.0.1 7838

===========================================================================

[work@db-testing-com06-vm3.db01.baidu.com net]$ ./server 7838 1

----等待新的连接到来开始新一轮聊天……

aaa

server: got connection from 127.0.0.1, port 32999, socket 4

准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方

消息:aaa

发送成功,共发送了3个字节!

接收消息成功:'yanggang nihao',共14个字节的数据

==========================

[work@db-testing-com06-vm3.db01.baidu.com net]$ ./client 127.0.0.1 7838

准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方

接收消息成功:'aaa',共3个字节的数据

yanggang nihao

消息:yanggang nihao

发送成功,共发送了14个字节!

===========================================================================

什么是异步通讯? 就是通讯任意一方可以任意发送消息,有消息来到时会收到系统提示去接收消息。 这里要用到select函数。使用步骤如下: 1、设置一个集合变量,用来存放所有要判断的句柄(file descriptors:即我们建立的每个socket、用open打开的每个文件等) 2、把需要判断的句柄加入到集合里 3、设置判断时间 4、开始等待,即select 5、如果在设定的时间内有任何句柄状态变化了就马上返回,并把句柄设置到集合里

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2010年10月25日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
加密通讯协议SSL编程周立发
编译程序用下列命令: gcc -Wall ssl-client.c -o client gcc -Wall ssl-server.c -o server 运行程序用如下命令: ./server 7838 1 127.0.0.1 cacert.pem privkey.pem ./client 127.0.0.1 7838 用下面这两个命令产生上述cacert.pem和privkey.pem文件: openssl genrsa -out privkey.pem 2048 openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095 具体请参考 “OpenSSL体系下使用密钥数字证书等” 如果想对SSL有更深入的了解,请学习计算机安全相关的内容,尤其是非对称加密技术。 如果想对SSL库的源代码有深入学习,请去 www.openssl.org 下载源码来阅读。
一见
2018/08/07
1.4K0
【C++】基础:网络编程介绍与TCP&UDP示例
网络传输模型可以抽象为7个层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
DevFrank
2024/07/24
3820
【C++】基础:网络编程介绍与TCP&UDP示例
linux网络编程系列(三)--tcp和udp的基本函数调用过程及如何选择
TCP是TCP/IP体系中面向连接的传输层协议,它提供全双工和可靠交付的服务。它采用许多机制来确保端到端结点之间的可靠数据传输,如采用序列号、确认重传、滑动窗口等。
cpp加油站
2021/04/16
9950
linux网络编程系列(三)--tcp和udp的基本函数调用过程及如何选择
Linux下Socket编程入门
网络字节序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节序采用big endian排序方式。
_咯噔_
2022/02/23
3.6K0
Linux下select的用法--实现一个简单的回射服务器程序
2. 函数说明:可以同时监控多个文件描述符是否发生了读写或者异常。(有点像windows下的waitformultipleobjects,可以同时等待多个事件) 参数说明: 1)nfds:要监控的文件描述符的最大值加1,这个值不能错。 2)readfds:指向fd_set的指针。这是一个集合,专门用于监视读取数据的。所有需要监控读取数据的描述符都需要放进这个集合中。比如你需要监控4描述符的读取数据,就把4放进这个集合之中。 3)writefds:同上,这里是专门监视写的集合 4)exceptfds:同上,这里是专门监视异常的集合 5)timeout:超时。指向的timeval 结构体。 如果参数设为NULL,则select是阻塞的。 如果不为空,则表示超时时间(当结构体里面的成员都设为0时,表示不阻塞,立即返回)。
xcywt
2022/05/09
6660
Linux网络编程TCP
TCP/IP 协议栈是一系列网络协议(protocol)的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输。
DeROy
2021/11/16
5.4K0
Linux网络编程TCP
提升性能的必备技术:Linux网络IO与select详解
IO 即“Input”和“Output”的组合,即输入/输出,IO用来处理设备之间的数据传输。socket/fd也是一种IO。
Lion Long
2024/08/10
1620
提升性能的必备技术:Linux网络IO与select详解
select()函数详解
http://www.cnblogs.com/Anker/archive/2013/08/14/3258674.html
bear_fish
2018/09/20
1.8K0
select()函数详解
20.7 OpenSSL 套接字SSL加密传输
OpenSSL 中的 SSL 加密是通过 SSL/TLS 协议来实现的。SSL/TLS 是一种安全通信协议,可以保障通信双方之间的通信安全性和数据完整性。在 SSL/TLS 协议中,加密算法是其中最核心的组成部分之一,SSL可以使用各类加密算法进行密钥协商,一般来说会使用RSA等加密算法,使用TLS加密针对服务端来说则需要同时载入公钥与私钥文件,当传输被建立后客户端会自行下载公钥并与服务端完成握手,读者可将这个流程理解为上一章中RSA的分发密钥环节,只是SSL将这个过程简化了,当使用时无需关注传输密钥对的问题。
微软技术分享
2023/11/05
4090
20.7 OpenSSL 套接字SSL加密传输
【Linux】I/O多路复用-SELECT/POLL/EPOLL
I/O多路复用 前言 文本相关参考资料及部分内容来源 《Linux高性能服务器编程》 《TCP/IP网络编程》 《Linux/UNIX系统编程手册》 ---- I/O多路复用核心思想为,使用一个线程,来处理多个客户端的请求。 或者说,使用一个特殊的fd,监视多个fd。 使得程序能同时监听多个文件描述符,这对提高程序的性能至关重要。 通常,网络程序在下列情况下需要使用I/O多路复用技术。 客户端程序需要同时处理多个socket。 客户端程序要同时处理用户输入和网络连接。 TCP服务器要同
半生瓜的blog
2023/05/13
1.1K0
【Linux】I/O多路复用-SELECT/POLL/EPOLL
一个简单的Linux下Client/Server应答例子
题目:Hello world 要求:案例程序基于TCP协议,由客户程序启动后向服务器程序发送“hello world”,服务器程序显示客户机IP地址、端口、以及发送的信息。服务器将收到的字符串发送给客户端,客户端显示验证。 使用方法:在linux下编译 $gcc -o client client.c $gcc -o server server.c 先运行server程序$./server 再运行client程序$./client xxx(你要访问服务器名---非IP)
阳光岛主
2019/02/19
1.2K0
【计算机网络】select/poll
多路转接属于 IO 复用方式的一种。系统提供 select() 函数来实现多路复用输入/输出模型。select 系统调用是用来让我们的程序监视多个文件描述符的状态变化的。程序会停在 select 这里等待,直到被监视的文件描述符有一个或多个发生了状态改变。
YoungMLet
2024/04/09
1360
【计算机网络】select/poll
多路I/O转接服务器
多路IO转接服务器也叫做多任务IO服务器。该类服务器实现的主旨思想是,不再由应用程序自己监视客户端连接,取而代之由内核替应用程序监视文件。
mindtechnist
2024/08/08
1220
多路I/O转接服务器
20.8 OpenSSL 套接字SSL传输文件
有了上面的基础那么传输文件的实现就变得简单了,在传输时通常我们需要打开文件,并每次读入1024个字节的数据包,通过SSL加密传输即可,此处的文件传输功能在原生套接字章节中也进行过详细讲解,此处我们还是使用原来的密钥对,实现一个服务端等待客户端上传,当客户端连接到服务端后则开始传输文件,服务端接收文件的功能。
微软技术分享
2023/11/06
2020
20.8 OpenSSL 套接字SSL传输文件
通过select 和状态EINPROGRESS 实现socket 连接超时判断
调用connect连接一般的超时时间是75s, 但是在程序中我们一般不希望等这么长时间采取采取动作。 可以在调用connect之前设置套接字非阻塞,然后调用connect,此时connect会立刻返回, 如果连接成功则直接返回0(成功), 如果没有连接成功,也会立即返回并且会设置errno为EINPROCESS,这并不是一个致命错误,仅仅是告知你已经在连接了,你只要判断是它就继续执行后面的逻辑就行了,比如select.通过select设置超时来达到为connect设定超时的目的. 下面的代码显示这个过程。
全栈程序员站长
2022/09/09
1.2K0
网络编程API-下 (I/O复用函数)[通俗易懂]
IO复用是Linux中的IO模型之中的一个,IO复用就是进程预先告诉内核须要监视的IO条件,使得内核一旦发现进程指定的一个或多个IO条件就绪,就通过进程进程处理。从而不会在单个IO上堵塞了。
全栈程序员站长
2022/07/08
4220
网络编程API-下 (I/O复用函数)[通俗易懂]
UDP&TCP Linux网络应用编程详解
暂时想不出什么好的应用场景, 目前想到目标就是实现让两个设备通过网络传输数据, 比如开发板和Linux主机之间传数据, 以后就可以实现开发板通过网络上报数据或者主机通过网络控制开发板。
韦东山
2020/09/30
5.8K0
UDP&TCP Linux网络应用编程详解
205-ESP32_SDK开发-TCP服务器(select方式,支持多连接,高速高并发传输)
https://www.cnblogs.com/orlion/p/6119812.html
杨奉武
2021/12/12
1.1K0
205-ESP32_SDK开发-TCP服务器(select方式,支持多连接,高速高并发传输)
I/O多路复用select/poll/epoll
早期操作系统通常将进程中可创建的线程数限制在一个较低的阈值,大约几百个。因此, 操作系统会提供一些高效的方法来实现多路IO,例如Unix的select和poll。现代操作系统中,线程数已经得到了极大的提升,如NPTL线程软件包可支持数十万的线程。
WindSun
2019/09/09
1.3K0
I/O多路复用select/poll/epoll
socket网络编程(三)——select多路复用问题
在上文《socket网络编程(二)—— 实现持续发送》我们提到了多客户端的时候,多台客户端发送数据到服务端的话,只能有一台客户端可以正常发送和接受数据,另外一台完全没有反应,那这个问题怎么解决呢?很多人可能第一反应想到利用多线程技术,线程多的话用线程池来维护。的确,多线程确实可以实现这个效果,但是,可能很多看见这个但是就不怎么开心了,却不知很多科学科技的进步都是这个但是引发的。但是一个多线程编程很麻烦又容易出错,二是如果连接有几千个的话,线程间切换的开销确实是很大。如果能够在一个线程里就实现这个效果的话,那该多好啊!
一点sir
2024/01/10
8370
相关推荐
加密通讯协议SSL编程周立发
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文