免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4562 | 回复: 19
打印 上一主题 下一主题

[C] 关于socket上的输入输出 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-06-02 16:05 |只看该作者 |倒序浏览
本帖最后由 hsum 于 2010-06-02 21:22 编辑

更新2:
问题原因查明了,服务端其实是正确的,每次write()后都传送了消息给客户端,问题在于服务端write()的间隔时间很短,客户端来不及从接收缓冲区读取这一次的信息,服务端就又发送了信息过来,这样客户端一次读取的就很可能是服务端多次发送来的信息了,只要在客户端调用sleep(),延时下,就很容易证明这个原因。。。。

现在想想看怎么解决这个问题呢



更新:
现在的问题是这样,我的需求是:客户端发送一个字符串给服务端,write(sockfd,string,strlen(string)),服务端接收到字符串后作出一些处理,这个处理过程中有一些输出,从一行至多行不等,需要返回给客户端,在客户端上显示.

我的客户端发送和接受是这么写的:

  1. char send[MAX_COMMAND];
  2. char receive[MAX_COMMAND];

  3. while(1){
  4.     bzero(send,MAX_COMMAND);
  5.     bzero(receive,MAX_COMMAND);
  6.    
  7.     printf("$:");
  8.     fgets(send,MAX_COMMAND,stdin);    // 获得输入的字符串
  9.     send[strlen(send)]='\n';
  10.     write(sockfd,send,strlen(send));     //发送给服务端

  11.     while(1){
  12.         bzero(receive,1024);
  13.         if((n=read(sockfd,receive,MAX_COMMAND))<=0){   //如果读取的字符数小于0,判断是否是因为缓冲区问题
  14.              if(errno==EINTR)
  15.                  continue;
  16.              else
  17.                  break;

  18.         }
  19.         if(!strcmp(receive,"\n\n\n"))    //如果服务端发送过来三个回车,说明本次发送完毕,跳出循环
  20.             break;
  21.         printf("%s",receive);    //打印本次返回的结果
  22.         }
  23. }
复制代码
服务端的代码:

  1. .......接受到客户端的指令,并调用相应函数,下面是相应函数中的内容
  2.         char newline[1024];
  3.         bzero(newline,1024);
  4.        
  5.         sprintf(newline,"aaaaaaaaa \n");
  6.         write(sockfd,newline,strlen(newline));
  7. //        sleep(2);

  8. .....都是这种输出格式

  9.         sprintf(newline,"zzzzzzzzzz \n");
  10.         write(sockfd,newline,strlen(newline));
  11. //        sleep(2);

  12.         strcpy(newline,"\n\n\n");           //最后发送三个回车,代表本次返回完毕
  13.         write(sockfd,newline,strlen(newline));
复制代码
问题就在这,并不是每次服务端碰到write(),客户端都输出相应内容,而是客户端一次接收到多个服务端的write内容(我在客户端通过read返回的字节数判断的),所以服务端最后代表结束的三个回车一同添加在前面的输出结果后面了,致使客户端不能接收到单独的三个回车,但奇怪的是,我在服务端每次调用完write()后,调用sleep(),这样就可以像我期望的那样了,服务端调用一次write(),便发送给客户断,客户端便接收到信息(通过客户端read返回的字节数),客户端也能正确识别最后三个回车了,这是为什么呢?

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------






最近的项目中用到客户端服务端,linux环境下c,第一次接触socket编程,一边在看<unix网络编程>,一边在写代码

客户端发送一条字符串给客户端(已经实现)
服务端接收到字符串后经过处理,产生结果,几行至几十行不等,需要回送给客户端显示,


我的方法是在服务端记录接收到的套接字socketfd,然后传入所有有输入的函数,这些函数原来是直接printf()输入,现在改为:
sprintf(string,""");    //先将输出存在一个字符串数组string中
write(socketfd,string,strlen(string));    //再将string输出到这个套接字中


问题:
有的输出很短,一行不到,几十个字符,客户端能够正常接收到并显示。
可是有的输入很长,10多行,几百个字符串,客户端不能正常显示,不如客户端输入命令a后,只显示了应有结果的一行,再随便输入一个命令或者回车,其余的十几行就显示出来了。


很奇怪,感觉是缓冲区的问题,但不晓得怎么搞,请指教!谢谢!

论坛徽章:
0
2 [报告]
发表于 2010-06-02 16:19 |只看该作者
用现成的libevent库吧,要不然新手+生手,调试花的时间比写程序的时间长N倍吧。
照里面的例子抄一个改改就行了。

论坛徽章:
0
3 [报告]
发表于 2010-06-02 16:52 |只看该作者
谢谢楼上的,不过还是准备自己写,呵呵。


现在发现一个解决的方法,我原来有问题的输出函数里面是这样的:
.....
sprintf(string,"");
write(socketfd,string,strlen(string));

sprintf(string,"");
write(socketfd,string,strlen(string));

sprintf(string,"");
write(socketfd,string,strlen(string));
.....

也就是说每次一有输出,我就把它写到套接口里面去,这样客户端接受到输入有问题,

现在我把上面的代码改成:
....
char *p;

sprintf(p,"");
p+=(int)strlen(p);

sprintf(p,"");
p+=(int)strlen(p);

sprintf(p,"");
p+=(int)strlen(p);
....
write(socketfd,string,strlen(string));

也就是不是碰到输入就写入套接口,而是全部先放到一个很大的字符串数组中,完了之后再一次写入套接口,这回客户端正常显示了。



有点不解,请高手指教

论坛徽章:
1
黑曼巴
日期:2020-02-27 22:54:26
4 [报告]
发表于 2010-06-02 17:26 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
5 [报告]
发表于 2010-06-02 17:37 |只看该作者
ls能说的稍微详细点吗

第一次接触socket编程,很多不了解,谢谢

论坛徽章:
5
未羊
日期:2014-08-07 15:42:10双子座
日期:2014-09-23 15:42:172015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:55:282022北京冬奥会纪念版徽章
日期:2015-08-10 16:30:32
6 [报告]
发表于 2010-06-02 17:40 |只看该作者
应该是客户端缓冲区大小的问题

论坛徽章:
0
7 [报告]
发表于 2010-06-02 18:33 |只看该作者
你得定一个通信协议,比如每个string以\n为结束标记。recv拿到完整的string才处理,否则继续recv并和原来不完整的做下拼接。

论坛徽章:
0
8 [报告]
发表于 2010-06-02 19:09 |只看该作者
加个包头吧,指示你的数据包长度。比如你发"abc"三个字母,那么就要发5个字节数据,
前2个字节是一个unsigned short,值是3;

论坛徽章:
0
9 [报告]
发表于 2010-06-02 19:50 |只看该作者
奇怪了,

我在服务端的函数里面让每个write()函数后面sleep(2),客户端就可以正常接受了,怎么会

论坛徽章:
0
10 [报告]
发表于 2010-06-02 20:44 |只看该作者
TCP_NODELAY and TCP_CORK basically control packet “Nagling,” or automatic concatenation of small packets into bigger frames performed by a Nagle algorithm. John Nagle, after whom this process was named, first implemented this as a way to fight Ford’s network congestion in 1984. (See IETF RFC 896 for more details.) The problem he solved was the so-called silly window syndrome, where congestion occurred simply because widespread terminal applications sent keystrokes one per packet, typically one byte of payload and 40 bytes of header, thus causing 4,000 percent overhead. Nagling became standard and was aggressively implemented over the Internet. It is now considered a default, but as we'll see, there are situations when turning it off is desirable.

参考网址:http://en.wikipedia.org/wiki/Nagle's_algorithm

多个send默认会合并了,你加上这个就不用sleep了,不过如果过了多个网络,IP包可能被分断的,所以稳定的internet程序肯定要接收时重新组包。

  1. int nodly = 1;
  2. setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char*)&nodly, sizeof(int));
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP