我正在移植构建在ACE Proactor框架之上的应用程序.该应用程序适用于VxWorks和Windows,但在使用librt的内核2.6.X.X的Linux(CentOS 5.5,WindRiver Linux 1.4和3.0)上无法运行.

我把问题缩小到一个非常基本的问题:

应用程序在套接字上开始异步(通过aio_read)读取操作,然后在同一个套接字上开始异步(通过aio_write)写入.由于协议是从应用程序结束初始化的,因此无法实现读取操作.

– 当套接字处于阻塞模式时,永远不会写入并且协议“挂起”.

– 使用O_NONBLOCK套接字时,写入成功,但读取无限期地返回“EWOULDBLOCK / EAGAIN”错误,永远不会恢复(即使重新启动AIO操作).

我经历了多个论坛,无法找到一个明确的答案,说明这是否应该可行(而且我做错了)或Linux AIO不可能.是否可以放弃AIO并寻求不同的实现(通过epoll / poll / select等)?

附件是一个示例代码,可以在非阻塞套接字上快速重现问题:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define BUFSIZE (100)

// Global variables

struct aiocb *cblist[2];

int theSocket;

void InitializeAiocbData(struct aiocb* pAiocb, char* pBuffer)

{

bzero( (char *)pAiocb, sizeof(struct aiocb) );

pAiocb->aio_fildes = theSocket;

pAiocb->aio_nbytes = BUFSIZE;

pAiocb->aio_offset = 0;

pAiocb->aio_buf = pBuffer;

}

void IssueReadOperation(struct aiocb* pAiocb, char* pBuffer)

{

InitializeAiocbData(pAiocb, pBuffer);

int ret = aio_read( pAiocb );

assert (ret >= 0);

}

void IssueWriteOperation(struct aiocb* pAiocb, char* pBuffer)

{

InitializeAiocbData(pAiocb, pBuffer);

int ret = aio_write( pAiocb );

assert (ret >= 0);

}

int main()

{

int ret;

int nPort = 11111;

char* szServer = "10.10.9.123";

// Connect to the remote server

theSocket = socket(AF_INET, SOCK_STREAM, 0);

assert (theSocket >= 0);

struct hostent *pServer;

struct sockaddr_in serv_addr;

pServer = gethostbyname(szServer);

bzero((char *) &serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;

serv_addr.sin_port = htons(nPort);

bcopy((char *)pServer->h_addr, (char *)&serv_addr.sin_addr.s_addr, pServer->h_length);

assert (connect(theSocket, (const sockaddr*)(&serv_addr), sizeof(serv_addr)) >= 0);

// Set the socket to be non-blocking

int oldFlags = fcntl(theSocket, F_GETFL) ;

int newFlags = oldFlags | O_NONBLOCK;

fcntl(theSocket, F_SETFL, newFlags);

printf("Socket flags: before=%o, after=%o\n", oldFlags, newFlags);

// Construct the AIO callbacks array

struct aiocb my_aiocb1, my_aiocb2;

char* pBuffer = new char[BUFSIZE+1];

bzero( (char *)cblist, sizeof(cblist) );

cblist[0] = &my_aiocb1;

cblist[1] = &my_aiocb2;

// Start the read and write operations on the same socket

IssueReadOperation(&my_aiocb1, pBuffer);

IssueWriteOperation(&my_aiocb2, pBuffer);

// Wait for I/O completion on both operations

int nRound = 1;

printf("\naio_suspend round #%d:\n", nRound++);

ret = aio_suspend( cblist, 2, NULL );

assert (ret == 0);

// Check the error status for the read and write operations

ret = aio_error(&my_aiocb1);

assert (ret == EWOULDBLOCK);

// Get the return code for the read

{

ssize_t retcode = aio_return(&my_aiocb1);

printf("First read operation results: aio_error=%d, aio_return=%d - That's the first EWOULDBLOCK\n", ret, retcode);

}

ret = aio_error(&my_aiocb2);

assert (ret == EINPROGRESS);

printf("Write operation is still \"in progress\"\n");

// Re-issue the read operation

IssueReadOperation(&my_aiocb1, pBuffer);

// Wait for I/O completion on both operations

printf("\naio_suspend round #%d:\n", nRound++);

ret = aio_suspend( cblist, 2, NULL );

assert (ret == 0);

// Check the error status for the read and write operations for the second time

ret = aio_error(&my_aiocb1);

assert (ret == EINPROGRESS);

printf("Second read operation request is suddenly marked as \"in progress\"\n");

ret = aio_error(&my_aiocb2);

assert (ret == 0);

// Get the return code for the write

{

ssize_t retcode = aio_return(&my_aiocb2);

printf("Write operation has completed with results: aio_error=%d, aio_return=%d\n", ret, retcode);

}

// Now try waiting for the read operation to complete - it'll just busy-wait, receiving "EWOULDBLOCK" indefinitely

do

{

printf("\naio_suspend round #%d:\n", nRound++);

ret = aio_suspend( cblist, 1, NULL );

assert (ret == 0);

// Check the error of the read operation and re-issue if needed

ret = aio_error(&my_aiocb1);

if (ret == EWOULDBLOCK)

{

IssueReadOperation(&my_aiocb1, pBuffer);

printf("EWOULDBLOCK again on the read operation!\n");

}

}

while (ret == EWOULDBLOCK);

}

提前致谢,

Yotam.

解决方法:

首先,O_NONBLOCK和AIO不混合.当相应的读或写不会被阻塞时,AIO将报告异步操作完成 – 并且使用O_NONBLOCK,它们永远不会阻塞,因此aio请求将始终立即完成(使用aio_return()给出EWOULDBLOCK).

其次,不要为两个同时发生的未完成的aio请求使用相同的缓冲区.在发出aio请求的时间和aio_error()告诉你已完成的时间之间,缓冲区应被视为完全禁止.

第三,AIO对同一文件描述符的请求排队,以便给出明智的结果.这意味着在读取完成之前不会发生写入 – 如果您需要先写入数据,则需要以相反的顺序发出AIO.以下工作正常,无需设置O_NONBLOCK:

struct aiocb my_aiocb1, my_aiocb2;

char pBuffer1[BUFSIZE+1], pBuffer2[BUFSIZE+1] = "Some test message";

const struct aiocb *cblist[2] = { &my_aiocb1, &my_aiocb2 };

// Start the read and write operations on the same socket

IssueWriteOperation(&my_aiocb2, pBuffer2);

IssueReadOperation(&my_aiocb1, pBuffer1);

// Wait for I/O completion on both operations

int nRound = 1;

int aio_status1, aio_status2;

do {

printf("\naio_suspend round #%d:\n", nRound++);

ret = aio_suspend( cblist, 2, NULL );

assert (ret == 0);

// Check the error status for the read and write operations

aio_status1 = aio_error(&my_aiocb1);

if (aio_status1 == EINPROGRESS)

puts("aio1 still in progress.");

else

puts("aio1 completed.");

aio_status2 = aio_error(&my_aiocb2);

if (aio_status2 == EINPROGRESS)

puts("aio2 still in progress.");

else

puts("aio2 completed.");

} while (aio_status1 == EINPROGRESS || aio_status2 == EINPROGRESS);

// Get the return code for the read

ssize_t retcode;

retcode = aio_return(&my_aiocb1);

printf("First operation results: aio_error=%d, aio_return=%d\n", aio_status1, retcode);

retcode = aio_return(&my_aiocb1);

printf("Second operation results: aio_error=%d, aio_return=%d\n", aio_status1, retcode);

或者,如果您不关心相互之间的读取和写入,您可以使用dup()为套接字创建两个文件描述符,并使用一个用于读取而另一个用于写入 – 每个都将具有AIO操作单独排队.

标签:linux,sockets,kernel,nonblocking,aio

来源: https://codeday.me/bug/20190630/1340573.html

linux 全双工 wifi热点,Linux中的同时套接字读/写(“全双工”)(特别是aio)相关推荐

  1. 用Linux做wifi热点/无线路由

    用Linux做wifi热点/无线路由 全文阅读 分步阅读 以fedora14为例安装hostapd,将Linux笔记本部署为一台高性能无限路由器,顺便说一句,我的fedora14安装在一台10英寸的上 ...

  2. C语言 socket shutdown()函数(将与 sockfd 关联的套接字上的全双工连接全部或部分关闭)

    man 2 文档 [root@ubuntu /arnold_test/20220324_hikflow_demo__socket_server_test]102# man -f shutdown sh ...

  3. linux 创建wifi 热点_Linux_ubuntu14.04怎么建立wifi热点?,创建的热点手机也是可以连接 - phpStudy...

    ubuntu14.04怎么建立wifi热点? 创建的热点手机也是可以连接的,这里将分享两个方法 一,kde-nm-connection-editor工具开启热点 在ubuntu软件中心搜索kde nm ...

  4. linux 4g wifi切换,Linux 开发板4G转WiFi热点 手机连接热点上网(二 4G模块的移植)...

    接着前一篇,本篇博文记录4G模块的移植. 我使用的模块是中兴ME3630模块,前面说了使用供应商或者官方的资料进行移植即可.一般来说4G模块的驱动,Linux内核也基本都有了,只需要设置一下optio ...

  5. linux 创建wifi 热点_Linux创建无线WIFI热点 2.4g/5g

    类库依赖 hostapd dnsmasq 创建hostapd.conf配置文件 2.4g wifi 热点hostapd.conf 配置文件 interface=wlan0 driver=nl80211 ...

  6. 开发版linux随身wifi,让linux下无线网卡变身随身wifi

    最痛苦的事莫过于--上班 最最痛苦的事莫过于--上班有网不能上 最最最痛苦的事莫过于--上班有网能上却没有wifi 最最最最痛苦的事莫过于--你有无线网卡却没有U口可插 最最最最最痛苦的事莫过于--有 ...

  7. linux串口编程实例_Linux 网络编程——原始套接字实例:发送 UDP 数据包

    以太网报文格式: IP 报文格式: UDP 报文格式: 校验和函数: /*******************************************************功能:校验和函数参 ...

  8. Linux 网络编程详解一(IP套接字结构体、网络字节序,地址转换函数)

    IPv4套接字地址结构 struct sockaddr_in {uint8_t sinlen;(4个字节)sa_family_t sin_family;(4个字节)in_port_t sin_port ...

  9. 【Linux网络编程】网络基础 和 socket套接字 服务器与客户端 详细案例说明

    目录 前言 一.网络编程三要素 1.IP地址 2.通信协议 3.端口号 二.SOCKET套接字 SOCKET概述 SOCKET分类 三.代码实现 1.编程思路 2.建立服务器 服务器完整代码 3.建立 ...

最新文章

  1. Linux-下载传输并安装启动Tomcat
  2. Java 8流:Micro Katas
  3. SpringBoot_Redis配置
  4. python用户输出怎么命名变量_python变量及用户交互,用户名格式化输出
  5. python读取word文件内容_[python]读取word文档中的数据,整理成excel表
  6. LanguageTool至少需要哪些jar包?
  7. EPLAN小知识——添加字体
  8. 可视化设计之迷失扁平化风潮
  9. Python每日一记127文本型数字转化为数值型数字(eval函数)
  10. 12306bypass推送
  11. 并行计算 Blog 02 —— SLIC代码的计算热点分析
  12. Rasa课程、Rasa培训、Rasa面试、Rasa实战系列之 Response Selection
  13. 心得体会标题大全_心得体会题目大全
  14. 学习心得:HSV颜色空间
  15. Unity3D播放音频数组的问题
  16. 黑名单挂断电话及删除电话记录
  17. 微信小程序抓包https抓包的血泪史
  18. PHP民俗文化管理系统,民俗文化
  19. 计算机考研零基础英语怎么复习,英语零基础怎么考研 上岸学姐来教你
  20. 先有鸿蒙后有天 华为,见风使舵墙头草,昔日代工巨头对华为翻脸不认,如今沦落至此...

热门文章

  1. .NET Standard 2.0 特性介绍和使用指南
  2. 自包含 .NET Core应用程序
  3. LINQ:进阶 - LINQ 标准查询操作概述
  4. Vue 深度监听和初始绑定
  5. yum search php7,yum install php7 in centos6
  6. 【QGIS入门实战精品教程】4.4:QGIS如何将点自动连成线、线生成多边形?
  7. 【遥感物候】Matlab求解一元六次多项式,计算植被生长季始期
  8. Android之ActivityManager与Proxy模式的运用
  9. 栈和队列之LinekedList(双端队列)
  10. git之Pushing to the remote branch is not fast-forward错误解决