Vxworks 中 tcp链接 client 端 recv时 如何设置超时等待?

时间:2023-01-05 00:50:47
最近做嵌入式网络通信 
客户端在等待接受信息时 如果 服务器端 异常断开
无法判断已断开网络
recv函数一直傻等 
如何设置才可以避免 其陷入等待 ?谢谢

11 个解决方案

#1


设定超时退出。
比方说recv函数所在的任务设置运行超时(可在任务内计时)自动删除此任务,不影响到其它任务执行。

#2


用I/O复用(select)去实现超时处理。还有一种是设置一个超时处理,超时之后设置一个错误值并关闭socket
使recv调用返回。

#3


感谢解答
应用了一个超时中断任务 看门狗
在recv时间达到看门狗设定时间后
我设置了函数close(Sock);
经过验证 发现确实关闭了套接字
因为服务器端套显示断开
但是客户端并没有退出recv并返回
任务陷入了无限阻塞中
具体函数这么写的不知道麻烦帮忙看下问题在哪:

建立套接字 并connect服务器的函数略过
以下为连接好后的函数  
while(true)  //循环recv
{
  wdID=wdCreat();   //建立看门狗
  wdStart(wdID,sysXXXX,func(abc),0);   //设定超时时间
  if(recvlen=recv(sockM,buff,bufflen,0) == 0)
  {
    close(sockM);
    break;
  }
  wdCancle(wdID);
  wdDelete(wdID);
}
int abc()
{
  close(sockM);
}
我摘主要的内容,超时后可以走abc这个函数 但是关闭套接字后 无法退出recv 函数 更退不出while循环
导致任务无法关闭
请教如何更改

#4


首先说明一下,由于WDOG是在DEC中间中执行的,所以直接调用close等是错误的,可以在里面用excJobAdd由tExcTask来完成这些执行。不过为了方便我下面就只更正一上编码错误了。

本端关闭之后再去recv应该是返回失败,你这里直接用==0判断会导致死循环吧。而且你这里反复地创建WDOG也会导致内存泄露吧。WDOG没有刷新的函数,可以取消之后重新开始,示例:

int iTmOut = 0;
wdID = wdCreate();
for ( ; ; )
{
    wdStart(wdID, XXX, MyTmOut, &iTmOut);
    if ((recvlen = recv(sockM, buff, bufflen, 0)) <= 0)
    {
        if (0 == iTmOut)
        {
            // 对端关闭
            close(sockM);
        }
        
        break;
    }

    // ......
}

int MyTmOut(int *pVal)
{
    *pVal = 1;
    close(sockM);
}

当然最好是用半关闭,这样close之前就不用再判断了。

#5


Sorry,刚才代码中忘了写全:
    if ((recvlen = recv(sockM, buff, bufflen, 0)) <= 0)
    {
        if (0 == iTmOut)
        {
            // 对端关闭
            close(sockM);
        }
        
        break;
    }

    wdCancel(wdID);

#6


调用wdstart有问题.

#7


调用  s1 = accept(sd, (struct sockaddr *)&their_addr, &addr_len);
    i = setsockopt(s1,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));
    i = setsockopt(s1,SOL_SOCKET,SO_SNDTIMEO,&timeout,sizeof(timeout));
好象不好使!   

#8


楼上的,这两个选项在VxWorks协议栈中是不支持的。

#9


这两个选项是支持的,请问你的vxWorks版本号是多少?

#10


我用过5.x。

#11


楼主您好,是否可以尝试将套接字设置为非阻塞方式?

blBlockflag = TRUE;//设置为非阻塞方式
ioctl(socket, FIONBIO, (INT32)&blBlockflag);

我写的代码是调用read()//此时read()不会阻塞,立刻返回
如果返回 -1 则表示超时
如果返回 0 表示对端关闭了socket
如果返回正数,表示接受到的字节数

这样,你就可以通过一个循环来实现超时退出了

/* 下面是我程序里的一部分,是要读取1个字节的启动字符 */
while (dwCounter < 30000)
{
    n = read(dwFd, (CHAR *)&cStartChar, 1);
    if (n == 0)
    {
        return NULL;//对端关闭了链路
    }
    if (n == -1)
    {
        dwCounter++;
taskDelay(1);
continue;
    }
    if (n != 1)
    {
        #ifdef P102IODEBUG
        logMsg("读取启动字符失败!!!\n", 0,0,0,0,0,0);
        #endif
cStartChar = 0;
continue;
    }
    break;
}

不知道这样的方法在楼主的程序里是否可行,
我们使用的接口不同,
但是应该有类似的方式。

#1


设定超时退出。
比方说recv函数所在的任务设置运行超时(可在任务内计时)自动删除此任务,不影响到其它任务执行。

#2


用I/O复用(select)去实现超时处理。还有一种是设置一个超时处理,超时之后设置一个错误值并关闭socket
使recv调用返回。

#3


感谢解答
应用了一个超时中断任务 看门狗
在recv时间达到看门狗设定时间后
我设置了函数close(Sock);
经过验证 发现确实关闭了套接字
因为服务器端套显示断开
但是客户端并没有退出recv并返回
任务陷入了无限阻塞中
具体函数这么写的不知道麻烦帮忙看下问题在哪:

建立套接字 并connect服务器的函数略过
以下为连接好后的函数  
while(true)  //循环recv
{
  wdID=wdCreat();   //建立看门狗
  wdStart(wdID,sysXXXX,func(abc),0);   //设定超时时间
  if(recvlen=recv(sockM,buff,bufflen,0) == 0)
  {
    close(sockM);
    break;
  }
  wdCancle(wdID);
  wdDelete(wdID);
}
int abc()
{
  close(sockM);
}
我摘主要的内容,超时后可以走abc这个函数 但是关闭套接字后 无法退出recv 函数 更退不出while循环
导致任务无法关闭
请教如何更改

#4


首先说明一下,由于WDOG是在DEC中间中执行的,所以直接调用close等是错误的,可以在里面用excJobAdd由tExcTask来完成这些执行。不过为了方便我下面就只更正一上编码错误了。

本端关闭之后再去recv应该是返回失败,你这里直接用==0判断会导致死循环吧。而且你这里反复地创建WDOG也会导致内存泄露吧。WDOG没有刷新的函数,可以取消之后重新开始,示例:

int iTmOut = 0;
wdID = wdCreate();
for ( ; ; )
{
    wdStart(wdID, XXX, MyTmOut, &iTmOut);
    if ((recvlen = recv(sockM, buff, bufflen, 0)) <= 0)
    {
        if (0 == iTmOut)
        {
            // 对端关闭
            close(sockM);
        }
        
        break;
    }

    // ......
}

int MyTmOut(int *pVal)
{
    *pVal = 1;
    close(sockM);
}

当然最好是用半关闭,这样close之前就不用再判断了。

#5


Sorry,刚才代码中忘了写全:
    if ((recvlen = recv(sockM, buff, bufflen, 0)) <= 0)
    {
        if (0 == iTmOut)
        {
            // 对端关闭
            close(sockM);
        }
        
        break;
    }

    wdCancel(wdID);

#6


调用wdstart有问题.

#7


调用  s1 = accept(sd, (struct sockaddr *)&their_addr, &addr_len);
    i = setsockopt(s1,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));
    i = setsockopt(s1,SOL_SOCKET,SO_SNDTIMEO,&timeout,sizeof(timeout));
好象不好使!   

#8


楼上的,这两个选项在VxWorks协议栈中是不支持的。

#9


这两个选项是支持的,请问你的vxWorks版本号是多少?

#10


我用过5.x。

#11


楼主您好,是否可以尝试将套接字设置为非阻塞方式?

blBlockflag = TRUE;//设置为非阻塞方式
ioctl(socket, FIONBIO, (INT32)&blBlockflag);

我写的代码是调用read()//此时read()不会阻塞,立刻返回
如果返回 -1 则表示超时
如果返回 0 表示对端关闭了socket
如果返回正数,表示接受到的字节数

这样,你就可以通过一个循环来实现超时退出了

/* 下面是我程序里的一部分,是要读取1个字节的启动字符 */
while (dwCounter < 30000)
{
    n = read(dwFd, (CHAR *)&cStartChar, 1);
    if (n == 0)
    {
        return NULL;//对端关闭了链路
    }
    if (n == -1)
    {
        dwCounter++;
taskDelay(1);
continue;
    }
    if (n != 1)
    {
        #ifdef P102IODEBUG
        logMsg("读取启动字符失败!!!\n", 0,0,0,0,0,0);
        #endif
cStartChar = 0;
continue;
    }
    break;
}

不知道这样的方法在楼主的程序里是否可行,
我们使用的接口不同,
但是应该有类似的方式。