免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3507 | 回复: 15

[C] Non-blocking下使用write发送socket数据 [复制链接]

论坛徽章:
0
发表于 2015-04-08 15:31 |显示全部楼层
本帖最后由 vesontio 于 2015-04-08 15:53 编辑

我在网上看关于non-blocking的socket发送数据的文章,很多都自己另外实现一个writen函数:

  1. int writen(int sock, unsigned char *buff, size_t len) {
  2.   size_t total, offset;
  3.   ssize_t ret;

  4.   offset = 0;
  5.   total = len;

  6.   while (total > 0) {
  7.     ret = write (fd, buff + offset, total)
  8.       if (ret < 0) {
  9.         if (errno == EAGAIN || errno == EWOULDBLOCK) {
  10.           continue;
  11.         }
  12.         else {
  13.           return -1;
  14.         }
  15.       }
  16.     total -= ret;
  17.     offset += ret;
  18.   }
  19.   return 0;
  20. }
复制代码
上面这段代码没测试过,但是大概就是这个逻辑。

基本说白了就是反复发,直到把 buff 彻底发出去为止。那么问题是:这种做法,与 blocking 何异?反正也是抓着这个 fd 不放,使劲发。
采用 non-blocking 本来就是想提高系统的反应能力吧,这样不发完就不让走的形式,会不会和初衷背道而驰?

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
发表于 2015-04-08 15:35 |显示全部楼层
你不这么写不就完了?你就不能在那个循环中顺便再干点别的?

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
发表于 2015-04-08 15:58 |显示全部楼层
本帖最后由 yulihua49 于 2015-04-08 16:06 编辑
vesontio 发表于 2015-04-08 15:31
我在网上看关于non-blocking的socket发送数据的文章,很多都自己另外实现一个writen函数:上面这段代码没测 ...

  1. int SendNet(int socket,char *buf,int n,int MTU)
  2. {
  3. int bcount,bw;
  4. int sz,i=0;
  5. int fflag;
  6. size_t SendSize;

  7.         if(socket<0) return SYSERR;
  8.         fflag=fcntl(socket,F_GETFL,0);
  9.         if(fflag != -1) fcntl(socket,F_SETFL,fflag|O_NONBLOCK); //异步操作
  10.         bcount=0;
  11.         bw=0;
  12.         if(MTU>500) SendSize=MTU;
  13.         else SendSize=n;
  14.         while(bcount<n){
  15.                 sz=MIN(n-bcount,SendSize);
  16.                 if((bw=write(socket,buf,sz))>0){
  17.                         bcount+=bw;
  18.                         buf+=bw;
  19.                 }
  20.                 if(bw<0&&errno!=EAGAIN) {
  21.                         ShowLog(1,"%s:err=%d,%s",__FUNCTION__,errno,strerror(errno));
  22.                         break;
  23.                 }
  24.                 if(bw < sz && fflag != -1) { //切换任务
  25. ShowLog(5,"%s:tid=%lX,socket=%d,yield bw=%d/%d",__FUNCTION__,pthread_self(),socket,bw,sz);
  26.                     i=do_event(socket,1,0); //yield by EPOLLOUT
  27.                     if(i<0) {//逃跑失败
  28.                         fcntl(socket,F_SETFL,fflag);
  29.                         fflag = -1;
  30.                     }
  31.                 }
  32.         }
  33.         if(fflag != -1)  fcntl(socket,F_SETFL,fflag);
  34.         return bcount==0?-1:bcount;
  35. }
复制代码
看27行,如果有可能,就yield to epoll,线程跑掉,当条件具备,就resume回来继续。
如果逃跑失败,就转成同步阻塞模式。
这个就是协程工作模式。AIO,NIO只有与协程结合才有意义。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
发表于 2015-04-08 16:13 |显示全部楼层
本帖最后由 yulihua49 于 2015-04-08 16:28 编辑
yulihua49 发表于 2015-04-08 15:58
看27行,如果有可能,就yield to epoll,线程跑掉,当条件具备,就resume回来继续。
如果逃跑失败,就转成 ...

  1. 5 FIRST:8  04/08 15:00'25 RecvNet:tid=7F50A46DB700,socket=21,yield bcount=0/68
  2. 5 FIRST:8  04/08 15:00'25 thread_work:tid=7F50A46DB700,fiber yield from TCB_no=8
  3. 5 midsc:15198 04/08 15:00'25 thread_work:7F50A46DB700 create fiber for TCB_no=18
  4. 2 midsc:15198 04/08 15:00'25 连接 127.0.0.1,TCB:17,timeout=360
  5. 4 midsc:15198 04/08 15:00'25 do_work: TCB_no=10,tid=7F50A460F700,PROTO_NUM=0 pkg_len=77,t_len=77,O_NODE=16777343,USEC=3637551625043920
  6. 3 FIRST:127.0.0.1:10 04/08 15:00'25 get_s_connect:get pool[0],TCB_no=10,tid:7F50A460F700,USEC=3637551625044062
  7. 5 FIRST:127.0.0.1:10 04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[0]=19
  8. 5 FIRST:127.0.0.1:10 04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[1]=19
  9. 5 FIRST:127.0.0.1:10 04/08 15:00'25 RecvNet:tid=7F50A460F700,socket=23,yield bcount=0/68
  10. 5 FIRST:127.0.0.1:10 04/08 15:00'25 thread_work:tid=7F50A460F700,fiber yield from TCB_no=10
  11. 5 midsc:15198 04/08 15:00'25 thread_work:7F50A460F700 create fiber for TCB_no=19
  12. 2 midsc:15198 04/08 15:00'25 连接 127.0.0.1,TCB:19,timeout=360
  13. 2 midsc:15198 04/08 15:00'25 连接 127.0.0.1,TCB:20,timeout=360
  14. 2 midsc:15198 04/08 15:00'25 连接 127.0.0.1,TCB:18,timeout=360
  15. 4 midsc:15198 04/08 15:00'25 do_work: TCB_no=15,tid=7F50A46DB700,PROTO_NUM=0 pkg_len=77,t_len=77,O_NODE=16777343,USEC=3637551625049720
  16. 3 FIRST:127.0.0.1:15 04/08 15:00'25 get_s_connect:get pool[0],TCB_no=15,tid:7F50A46DB700,USEC=3637551625049876
  17. 5 FIRST:127.0.0.1:15 04/08 15:00'25 get_SC_weight:tid=7F50A46DB700,DNODE[1} weight[0]=18
  18. 5 FIRST:127.0.0.1:15 04/08 15:00'25 get_SC_weight:tid=7F50A46DB700,DNODE[1} weight[1]=19
  19. 2 midsc:15198 04/08 15:00'25 连接 127.0.0.1,TCB:21,timeout=360
  20. 5 FIRST:7  04/08 15:00'25 do_work:call_back TCB_no=7,tid=7F50A460F700,USEC=3637551625050727
  21. 3 FIRST:7  04/08 15:00'25 from_client:TCB:7,tid=7F50A460F700,Send to serv proto_num=0X000A,t_cont=-2147483646,SendPack ret=0,USEC=3637551625050774
  22. 4 midsc:15198 04/08 15:00'25 do_work: TCB_no=13,tid=7F50A460F700,PROTO_NUM=0 pkg_len=77,t_len=77,O_NODE=16777343,USEC=3637551625050810
  23. 3 FIRST:127.0.0.1:13 04/08 15:00'25 get_s_connect:get pool[0],TCB_no=13,tid:7F50A460F700,USEC=3637551625050935
  24. 5 FIRST:127.0.0.1:13 04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[0]=18
  25. 5 FIRST:127.0.0.1:13 04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[1]=18
  26. 5 FIRST:127.0.0.1:13 04/08 15:00'25 RecvNet:tid=7F50A460F700,socket=25,yield bcount=0/68
  27. 5 FIRST:127.0.0.1:13 04/08 15:00'25 thread_work:tid=7F50A460F700,fiber yield from TCB_no=13
  28. 5 midsc:15198 04/08 15:00'25 thread_work:7F50A460F700 create fiber for TCB_no=14
  29. 4 midsc:15198 04/08 15:00'25 do_work: TCB_no=14,tid=7F50A460F700,PROTO_NUM=0 pkg_len=77,t_len=77,O_NODE=16777343,USEC=3637551625052286
  30. 3 FIRST:127.0.0.1:14 04/08 15:00'25 get_s_connect:get pool[0],TCB_no=14,tid:7F50A460F700,USEC=3637551625052427
  31. 5 FIRST:127.0.0.1:14 04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[0]=17
  32. 5 FIRST:127.0.0.1:14 04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[1]=18
  33. 5 FIRST:127.0.0.1:14 04/08 15:00'25 RecvNet:tid=7F50A460F700,socket=26,yield bcount=0/68
  34. 5 FIRST:127.0.0.1:14 04/08 15:00'25 thread_work:tid=7F50A460F700,fiber yield from TCB_no=14
  35. 5 FIRST:11  04/08 15:00'25 thread_work:7F50A460F700 create fiber for TCB_no=11
  36. 4 FIRST:11  04/08 15:00'25 do_work: TCB_no=11,tid=7F50A460F700,PROTO_NUM=0 pkg_len=0,t_len=0,O_NODE=4187505156,USEC=3637551625053288
  37. 3 FIRST:11  04/08 15:00'25 get_s_connect:get pool[0],TCB_no=11,tid:7F50A460F700,USEC=3637551625053304
  38. 5 FIRST:11  04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[0]=17
  39. 5 FIRST:11  04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[1]=17
  40. 5 FIRST:127.0.0.1:15 04/08 15:00'25 RecvNet:tid=7F50A46DB700,socket=24,yield bcount=0/68
  41. 5 FIRST:127.0.0.1:15 04/08 15:00'25 thread_work:tid=7F50A46DB700,fiber yield from TCB_no=15
  42. 5 midsc:15198 04/08 15:00'25 thread_work:7F50A46DB700 create fiber for TCB_no=22
  43. 5 FIRST:11  04/08 15:00'25 RecvNet:tid=7F50A460F700,socket=27,yield bcount=0/68
  44. 5 FIRST:11  04/08 15:00'25 thread_work:tid=7F50A460F700,fiber yield from TCB_no=11
  45. 5 midsc:15198 04/08 15:00'25 thread_work:7F50A460F700 create fiber for TCB_no=16
  46. 4 midsc:15198 04/08 15:00'25 do_work: TCB_no=16,tid=7F50A460F700,PROTO_NUM=0 pkg_len=77,t_len=77,O_NODE=16777343,USEC=3637551625054158
  47. 3 FIRST:127.0.0.1:16 04/08 15:00'25 get_s_connect:get pool[0],TCB_no=16,tid:7F50A460F700,USEC=3637551625054285
  48. 5 FIRST:127.0.0.1:16 04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[0]=16
  49. 5 FIRST:127.0.0.1:16 04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[1]=17
  50. 5 FIRST:127.0.0.1:16 04/08 15:00'25 RecvNet:tid=7F50A460F700,socket=28,yield bcount=0/68
  51. 5 FIRST:127.0.0.1:16 04/08 15:00'25 thread_work:tid=7F50A460F700,fiber yield from TCB_no=16
  52. 5 midsc:15198 04/08 15:00'25 thread_work:7F50A460F700 create fiber for TCB_no=9
  53. 4 midsc:15198 04/08 15:00'25 do_work: TCB_no=9,tid=7F50A460F700,PROTO_NUM=0 pkg_len=77,t_len=77,O_NODE=16777343,USEC=3637551625055294
  54. 3 FIRST:127.0.0.1:9 04/08 15:00'25 get_s_connect:get pool[0],TCB_no=9,tid:7F50A460F700,USEC=3637551625055422
  55. 5 FIRST:127.0.0.1:9 04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[0]=16
  56. 5 FIRST:127.0.0.1:9 04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[1]=16
  57. 5 FIRST:127.0.0.1:9 04/08 15:00'25 RecvNet:tid=7F50A460F700,socket=29,yield bcount=0/68
  58. 5 FIRST:127.0.0.1:9 04/08 15:00'25 thread_work:tid=7F50A460F700,fiber yield from TCB_no=9
  59. 5 FIRST:12  04/08 15:00'25 thread_work:7F50A460F700 create fiber for TCB_no=12
  60. 4 FIRST:12  04/08 15:00'25 do_work: TCB_no=12,tid=7F50A460F700,PROTO_NUM=0 pkg_len=0,t_len=0,O_NODE=2557866597,USEC=3637551625056254
  61. 3 FIRST:12  04/08 15:00'25 get_s_connect:get pool[0],TCB_no=12,tid:7F50A460F700,USEC=3637551625056270
  62. 5 FIRST:12  04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[0]=15
  63. 5 FIRST:12  04/08 15:00'25 get_SC_weight:tid=7F50A460F700,DNODE[1} weight[1]=16
  64. 5 FIRST:12  04/08 15:00'25 RecvNet:tid=7F50A460F700,socket=30,yield bcount=0/68
  65. 5 FIRST:12  04/08 15:00'25 thread_work:tid=7F50A460F700,fiber yield from TCB_no=12
  66. 5 FIRST:8  04/08 15:00'25 thread_work:tid=7F50A460F700,resume to TCB_no=8

复制代码
第二行:tid=7F50A46DB700,fiber yield from TCB_no=8;线程DB700从TCB_no=8 逃出。
下一行它就为TCB_no=18服务了。
66行,TCB_no=8终于resume了,但是线程变为7F50A460F700了。

中间,一群线程抢一堆任务,好乱呀。

论坛徽章:
0
发表于 2015-04-08 16:16 |显示全部楼层
本帖最后由 vesontio 于 2015-04-08 16:16 编辑

回复 3# yulihua49


你好,这个 do_event 我猜就是所谓的“先去干别的事情吧”,那具体实现的时候是做什么操作呢?

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
发表于 2015-04-08 16:32 |显示全部楼层
本帖最后由 yulihua49 于 2015-04-08 16:33 编辑
vesontio 发表于 2015-04-08 16:16
回复 3# yulihua49

多线程协程的工作日志。搜一下AIO,ASIO,协程,纤程。。。。。
AIO,NIO如果不与协程结合就没有实际意义。

论坛徽章:
12
巳蛇
日期:2013-09-16 15:32:242015年辞旧岁徽章
日期:2015-03-03 16:54:152015年亚洲杯之约旦
日期:2015-02-11 14:38:37双鱼座
日期:2015-01-05 11:05:47戌狗
日期:2014-12-08 09:41:18戌狗
日期:2014-08-15 09:29:29双子座
日期:2014-08-05 09:17:17卯兔
日期:2014-06-08 15:32:18巳蛇
日期:2014-01-27 08:47:08白羊座
日期:2013-11-28 21:04:15巨蟹座
日期:2013-11-13 21:58:012015年亚洲杯之科威特
日期:2015-04-17 16:51:51
发表于 2015-04-08 16:40 |显示全部楼层
6楼扯远了吧。

正常逻辑在遇到EAGAIN的时候向epoll注册可写事件,然后去处理其他任务。缓冲区中剩余的数据待可写事件触发后继续写。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
发表于 2015-04-08 17:06 |显示全部楼层
回复 4# yulihua49

你一下给他灌这么多就不怕把他吓跑了?


楼主需要搞清楚一个基本概念,Nonblocking I/O的目的是确保操作流程不会有“意外”的阻塞,有了这个保证,你就可以在同一个流程中安排多组操作而不会有相互影响,这种做法就是“复用”。
所以,Nonblocking I/O天生就是要配合其它东西使用的,单独的一个NIO怎么做都没什么意义。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
发表于 2015-04-09 10:04 |显示全部楼层
本帖最后由 yulihua49 于 2015-04-09 20:57 编辑
zhaohongjian000 发表于 2015-04-08 16:40
6楼扯远了吧。

正常逻辑在遇到EAGAIN的时候向epoll注册可写事件,然后去处理其他任务。缓冲区中剩余的数 ...

嗯。你那个是callback形式,IO完成后callback应用逻辑。continuations模型的两种形式:callback和coroutine。callback是由IO函数调用应用,coroutine是应用调用IO函数。
所以改成这样:
AIO,NIO脱离continuations,就没有什么实际意义,与上面哥们是一个意思。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
发表于 2015-04-09 14:11 |显示全部楼层
回复 9# yulihua49

continuation,没有“e”,你拼错了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP