helun 发表于 2013-11-29 16:20

socket的两个问题 大牛指点


1
创建socket的时候 我们可以设置它为阻塞或者非阻塞,那么在recv/send时,flag参数指定的阻塞和非阻塞和socket本身有没有关系没有、

从驱动层面分析,如果socket阻塞的时候,从socket读数据都为阻塞的。如果是这样那么recv时指定的flag参数如何解释 ,是忽略它呢 还是重新将socket指定为
flag指定的方式(阻塞或非阻塞)进行读写数据,求大牛指点

2
recv数据的时候,我们recv一次有可能数据接收不完,但是到底要recv多少次才算完呢?

int buf;

i = 0;
alllen = 0;
while(1)
{
        len = recv(socket,buf, 512, 0);
        if (len > 0)
        {       
                alllen += len;
                /* framedata为真正完整想要数据的缓冲,可以认为很大 */
                putbuf(framedata + i * 512 , buf, len);
                if (len <512 )
                        break;
                i++;
        }

}
deal(framedata, alllen);

像上面的代码 猛看起来没问题,但是仔细分析还是存在问题的,如果想要的数据 2050字节,那么我recv 5次即可以收完,
但是如果想要的数据是2048字节 就存在问题,recv完成4次后,还会一直在接收数据,何时是个头呀 ?
请教大牛这时 如何判断数据接收完成。
请注意前提是你不知道对方发的一包长度是多少,可能是2050也可能是2048? 这时 如何准确判断收完完整的一包数据?



pirloofmilan 发表于 2013-11-29 17:11

本帖最后由 pirloofmilan 于 2013-11-29 17:16 编辑

创建socket的时候 我们可以设置它为阻塞或者非阻塞,那么在recv/send时,flag参数指定的阻塞和非阻塞和socket本身有没有关系没有
int socket(int domain, int type, int protocol);
创建socket的时候是没有办法指定其是否阻塞的
可以通过setsockopt或者fcntl设置socket为阻塞或者非阻塞的
有4种组合
1. socket阻塞,recv/send默认:阻塞处理
2. socket阻塞,recv/send指定非阻塞:非阻塞处理
3. socket非阻塞,recv/send默认:非阻塞处理
4. socket非阻塞,recv/send指定非阻塞:非阻塞处理

从驱动层面分析,如果socket阻塞的时候,从socket读数据都为阻塞的。如果是这样那么recv时指定的flag参数如何解释 ,是忽略它呢 还是重新将socket指定为
flag指定的方式(阻塞或非阻塞)进行读写数据
就是上面的情况1和2

recv数据的时候,我们recv一次有可能数据接收不完,但是到底要recv多少次才算完呢?

recv默认阻塞,如果socket上面没有数据可读,那么recv就会一直阻塞在那里,直到有数据进入socket,像你说的这种情况,我们就必须预知数据的长度,比如HTTP协议就会在其头部有一个content length字段,告诉客户端我有多少数据要发过来。
也就是说客户端和服务器端必须按照一定的规则进行通信,这就是RFC定义的那些协议(比如HTTP DNS等等)存在的必要性了
当然,为了程序的健壮性,我们必须考虑特殊情况,比如客户端去读socket,但是此时服务器端却关掉了,那么此时recv是不是就永远阻塞了?但是我们可以设置一个timeout时间,比如超过30s读不到,那就失败返回,或者retry,等到服务器恢复正常,我们就可以再次读到数据了

总之,socket编程的真正难度是怎么处理各种异常情况

helun 发表于 2013-11-29 19:37

首先谢谢大牛
第1个问题你是验证过的吗 还是说在哪里看的?
明白了 我原来说的创建SOCKET时设置阻塞和非阻塞意思 是指用setsockopt或fcntl,是我没表述清楚谢谢纠正
recv的时候 ,利用超时是不错的方案(如果到来数据长度不定的话)

gotojyh 发表于 2013-11-29 21:12

用select或者epoll模型时,当有数据时,通知程序,然后再调用recv(就是确定有数据再调用)
如果不用的话在长度不定的时候应该只能阻塞等待或者非阻塞循环

linux_c_py_php 发表于 2013-12-01 11:10

建议多读书,闭门造车进步太慢。

backupyan 发表于 2013-12-31 01:03

问题很好,回答很好,学习了!

chengtao786 发表于 2014-02-11 10:27

赞,学习了。

xugr123 发表于 2014-02-12 10:46

最理想的情况,接收的数据有结束标示,每次接收,判断数据是否接收完。比如用pop3接收邮件的时候,由于邮件格式是标准的(rfc文档规定),邮件是以“.\r\n”结束的,这样就可以判断邮件是否完整
页: [1]
查看完整版本: socket的两个问题 大牛指点