socket堵塞的解决方法

进行网络开发会出现堵塞的情况,一般来说,会有三种解决办法:

  1. 在头部约定好数据的长度。当读取到的长度等于这个长度时就不再继续调用recv方法
  2. 约定结束标志,当读到该结束标志时退出不再recv
  3. 设置超时,会在设置的超时时间到达后退出而不再阻塞

第一种方法简单实用,但是如果返回头信息中是transfer-encoding:chunked,即分块传输的情况无法使用;
第二种方法碰到比较复杂的返回不好处理;
第三种可以,但是对网络的要求比较高。

对于分块传输的情况则不能通过Content-Length:xx来获取报文长度,我是通过设置超时来解决的,代码如下:

while(1)
    {
        FD_ZERO(&rfds);//清空描述符集合 
        FD_SET(0, &rfds);//将标准输入(stdin)添加到集合中
        FD_SET(socket_fd, &rfds);//将我们的套接字描述符添加到集合中
        /*设置超时时间*/
        timeout.tv_sec = 1;   
        timeout.tv_usec = 0;
        /*监听套接字是否超时*/
        if(select(socket_fd+1, &rfds, NULL, NULL, &timeout) <= 0)break;
        memset(lpbuf2,0,BUFFER_SIZE);
        bytes_received = recv(socket_fd, lpbuf2, BUFFER_SIZE, 0);
        /*获取网络字节*/
        if(bytes_received > 0)
        {
            strncpy(res,lpbuf2,bytes_received);
            sprintf(response + strlen(response),"%s",res);
        }
    }

获取的字符串是如下的形式:
head: headdata\r\n ………头信息
\r\n
len1\r\n ….分块传输的第一块的长度
body1\r\n …..分块传输的第一块
len2\r\n …..分块传输的第二块的长度
body2\r\n …..分块传输的第二块
…\r\n ……………分块传输的第n块的长度和第n块
0\r\n ………..结束符
\r\n

可以发现,约定了结束标志\r\n0\r\n,可以使用第三种方法,感兴趣的可以自己试试,然后是对获取的如上形式的字符串解析,获取body1body2这样形式的真正的内容。
代码如下:

char *http_parse_result(const char*lpbuf)
{
    char *ptmp = NULL; 
    static char response[16384] = "";
    int len;
    char chunkedbody[16384] = "";
    ptmp = (char*)strstr(lpbuf,"HTTP/1.1");
    if(!ptmp){
        printf("http/1.1 not faind\n");
        return NULL;
    }
    if(atoi(ptmp + 9)!=200){
        printf("result:\n%s\n",lpbuf);
        return NULL;
    }

    ptmp = (char*)strstr(lpbuf,"\r\n\r\n");//\r\n\r\n1fbd\r\nbody\r\n1223\r\nbody\r\n0\r\n\r\n
    if(!ptmp){
        printf("ptmp is NULL\n");
        return NULL;
    }
    ptmp = ptmp + 4;//1fbd\r\nbody\r\n1223\r\nbody\r\n0\r\n\r\n
    printf("ptmp=%s\n",ptmp);
    while(*ptmp != '\0')
    {
        len = strtol(ptmp,NULL,16);
        if(len == 0)
        {
            response[strlen(response)] = '\0';
            break;
        }
        printf("len=%d\n",len);
        ptmp = (char*)strstr(ptmp,"\r\n");//\r\nbody1\r\n1223\r\nbody2\r\n0\r\n\r\n
        strncpy(chunkedbody,ptmp + 2,len);
        printf("chunkedbody=%s\n",chunkedbody);
        sprintf(response+strlen(response),"%s",chunkedbody);
        memset(chunkedbody,0,16384);
        ptmp = ptmp + len + 4;//1223\r\nbody2\r\n0\r\n\r\n
    }
    return response;
}

就这样,有一点需要注意的是获取的网络字节是unicode形式的,需要先编码再解析。

你可能感兴趣的:(网络,程序,socket,网络,堵塞)