免费注册 查看新帖 |

Chinaunix

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

求助:socket故障!!! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-08-25 20:13 |只看该作者 |倒序浏览
服务器端 Redhat ES5:
int main()
{
    int mySock = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in myAddr;
    myAddr.sin_family=AF_INET;
    myAddr.sin_port=htons(2000);
    myAddr.sin_addr.s_addr=INADDR_ANY;

    bind(mySock,(sockaddr*)(&myAddr),sizeof(sockaddr));
    listen(mySock,5);

    int newSock;
    sockaddr_in clientAddr;
    socklen_t addrLen=sizeof(clientAddr);

    char recvBuf[100]={0};
    char sendBuf[100]={0};
    strcpy(sendBuf,"Hello 12345");

    while(1)
    {
        newSock=accept(mySock,(sockaddr*)(&clientAddr),&addrLen);
        recv(newSock,recvBuf,100,0);
        printf("%s\n",recvBuf);
        send(newSock,sendBuf,strlen(sendBuf),0);
        close(newSock);
    }
    return 0;
}

客户端 windows 2003、xp:
    SOCKET sockClient;
    sockClient=socket(AF_INET,SOCK_STREAM,0);
    if(sockClient==INVALID_SOCKET)
    {
        AfxMessageBox("创建套接字失败!");
        return 1;
    }

    SOCKADDR_IN addrServ;
    addrServ.sin_addr.S_un.S_addr=inet_addr(ServerIP);
    addrServ.sin_port=htons(2000);
    addrServ.sin_family=AF_INET;

    if((connect(sockClient,(sockaddr*)&addrServ,sizeof(sockaddr)))==SOCKET_ERROR)
    {
        AfxMessageBox("连接服务器失败!");
        return 1;
    }

    char Recvbuf[100]={0};

    char SendSN[100]={0};
    strcpy(SendSN,"20080101");

    send(sockClient,SendSN,strlen(SendSN)+1,0);
    recv(sockClient,Recvbuf,100,0);

    AfxMessageBox(Recvbuf);
    closesocket(sockClient);



现象:
  以上代码在局域网内通信正常。
  当用server公网IP通信时,client端发送后server端无反应,
  只有当client程序关闭那一刻,server才打印出recvBuf的内容。
  后来试了几个ADSL动态IP,也有同样现象。
抓包:
  三次握手完成后,client发出数据包,通信暂停。
  当client程序关闭时,发出了一个Reset包,server才继续执行打印出recvBuf信息。
问题:
  是我的代码问题?还是网络问题?


[ 本帖最后由 zhaocong94005 于 2008-8-25 20:33 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2008-08-25 20:39 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
3 [报告]
发表于 2008-08-25 20:46 |只看该作者

回复 #1 zhaocong94005 的帖子

很久没写网络程序了,你应该注意一下recv的返回条件(俺不记得了,也许是我说的原因),服务器recv一次接收100个字节,但是客户端却并没有发送那么多数据,自然会阻塞了。当客户端关闭的时候,recv当然就返回了。如果是局域网内,那么客户端关闭的数据包很快能够送给服务器,所以你观察不出来这个问题。当然,还是要试过才知道。

论坛徽章:
0
4 [报告]
发表于 2008-08-25 21:17 |只看该作者

回复 #3 xiexiecn 的帖子

我觉得是您说的问题,阻塞在recv这儿了。 但是怎么解决呢? 
二楼的方法不行。

论坛徽章:
0
5 [报告]
发表于 2008-08-25 21:25 |只看该作者
fflush(stdout);

论坛徽章:
0
6 [报告]
发表于 2008-08-25 21:27 |只看该作者
是数据在缓冲区,没发出吧?

论坛徽章:
4
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:56:11IT运维版块每日发帖之星
日期:2016-08-11 06:20:00IT运维版块每日发帖之星
日期:2016-08-15 06:20:00
7 [报告]
发表于 2008-08-25 21:35 |只看该作者

回复 #4 zhaocong94005 的帖子

因为你的代码中的recv和send调用都是堵塞方式的,接收或发送时应使用select或poll并设置超时(timeout)。你可以调用如下的函数来接收数据包:

int tcprecvdata(int sock,void* data,int size,int timeout)
{
        int byteleft;
        int result;
        unsigned char* p;
        fd_set read_set;
        fd_set exception_set;
        struct timeval t;

        if(data==NULL)
        {
#ifdef __DEBUG__
                fprintf(stderr,"%s,%d:tcprecvdata argument data is NULL.\n",
                        __FILE__,__LINE__);
#endif
                return(-1);
        }
        p=(unsigned char*)data;
        byteleft=size;
        FD_ZERO(&read_set);
        FD_ZERO(&exception_set);
        while(byteleft>0)
        {
                FD_CLR(sock,&read_set);
                FD_CLR(sock,&exception_set);
                FD_SET(sock,&read_set);
                FD_SET(sock,&exception_set);
                if(timeout <= 0)
                {
                        result=select(sock+1,&read_set,NULL,&exception_set,NULL);
                }
                else
                {
                        t.tv_usec = 0;
                        t.tv_sec = timeout;
                        result=select(sock+1,&read_set,NULL,&exception_set,&t);
                }
               
                if(result<0)
                {
#ifdef __DEBUG__
                        fprintf(stderr,"%s,%d:tcprecvdata call select failed:%s.\n",
                                __FILE__,__LINE__,strerror(errno));
#endif
                        return(-1);
                }
                else if(result==0)
                {
#ifdef __DEBUG__
                        fprintf(stderr,"%s,%d:tcprecvdata call select timeout.\n",
                                __FILE__,__LINE__);
#endif
                        return(0);
                }
               
                if(FD_ISSET(sock, &read_set))
                {
                        result=read(sock,p,byteleft);
                        if(result<0)
                        {
#ifdef __DEBUG__
                                fprintf(stderr,"%s,%d:tcprecvdata call read failed:%s.\n",
                                        __FILE__,__LINE__,strerror(errno));
#endif
                                return(-1);
                        }
                        if(result == 0)
                        {
#ifdef __DEBUG__
                                fprintf(stderr, "%s,%d:tcprecvdata call read return 0, remote close connection? errno:%d, error info:%s.\n",
                                        __FILE__, __LINE__, errno, strerror(errno));
#endif
                                return(-1);
                        }
                        byteleft-=result;
                        p+=result;
                        continue;
                }
                /*exception not support*/
                return(-1);
        }
        return(1);
}

论坛徽章:
0
8 [报告]
发表于 2008-08-25 21:46 |只看该作者

回复 #6 benbenr 的帖子

发出去了,抓包可以看到。

论坛徽章:
0
9 [报告]
发表于 2008-08-25 23:34 |只看该作者

回复 #4 zhaocong94005 的帖子

怎么解决,我想你可以改成只读取strlen(SendSN)+1这个长度试试看,9个字符吧。你这是小程序,recv(newSock,recvBuf,100,0);,100改成9看看行不行。如果具体应用的网络程序,我想肯定是会定义一套自己的协议啦,数据往来是会在数据流里有个长度的字段来标志的,那么根据长度来读取。
还有一个办法是半关闭,用shutdown不要用close,你的客户端数据发送完了,就来个shutdown,有个参数的,具体怎么用查man 。

论坛徽章:
0
10 [报告]
发表于 2008-08-26 09:23 |只看该作者

回复 #9 xiexiecn 的帖子

按您说的,recv长度改为9时就没问题了。
多谢提醒!!!! 现在明白了问题的根源。
我再琢磨琢磨有没有更好的方法。

谢谢诸位。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP