Linux的TCP连接与选择()在TESTSERVER失败 [英] Linux TCP connect with Select() fails at testserver
问题描述
我的问题如下:
我在Linux下编程接口通过以太网来控制GPIB控制器。要做到这一点我打开一个TCP套接字,并只发送命令到控制器。这是工作的罚款至今。我在写一些我的接口单元测试都发生问题:
要检查我使用从boost的lib一个tcp受体在一个单独的线程,只是连接到它,而不是实际控制人。这是工作压力太大,但只只要从接口的connect()调用阻止。但是因为我需要为连接指定的超时()调用我不得不用select()函数连接:
My problem is the following: I'm programming an Interface in Linux to control a GPIB Controller via Ethernet. To do so I open a TCP socket and just send the commands to the Controller. This is working fine so far. The problem I have occured at writing some kind of unit test for my Interface: To check I am using a tcp acceptor from boost lib in a seperate thread and just connect to it instead of the actual controller. This is working too, but only as long as the connect() call from the interface is blocking. However since I need a specified timeout for the connect() call I had to connect with the select() function:
// Open TCP Socket
m_Socket = socket(PF_INET,SOCK_STREAM,0);
if( m_Socket < 0 )
{
m_connectionStatus = STATUS_CLOSED;
return ERR_NET_SOCKET;
}
struct sockaddr_in addr;
inet_aton(m_Host.c_str(), &addr.sin_addr);
addr.sin_port = htons(m_Port);
addr.sin_family = PF_INET;
// Set timeout values for socket
struct timeval timeouts;
timeouts.tv_sec = SOCKET_TIMEOUT_SEC ; // const -> 5
timeouts.tv_usec = SOCKET_TIMEOUT_USEC ; // const -> 0
uint8_t optlen = sizeof(timeouts);
if( setsockopt( m_Socket, SOL_SOCKET, SO_RCVTIMEO,&timeouts,(socklen_t)optlen) < 0 )
{
m_connectionStatus = STATUS_CLOSED;
return ERR_NET_SOCKET;
}
// Set the Socket to TCP Nodelay ( Send immediatly after a send / write command )
int flag_TCP_nodelay = 1;
if ( (setsockopt( m_Socket, IPPROTO_TCP, TCP_NODELAY,
(char *)&flag_TCP_nodelay, sizeof(flag_TCP_nodelay))) < 0)
{
m_connectionStatus = STATUS_CLOSED;
return ERR_NET_SOCKET;
}
// Save Socket Flags
int opts_blocking = fcntl(m_Socket, F_GETFL);
if ( opts_blocking < 0 )
{
return ERR_NET_SOCKET;
}
int opts_noblocking = (opts_blocking | O_NONBLOCK);
// Set Socket to Non-Blocking
if (fcntl(m_Socket, F_SETFL, opts_noblocking)<0)
{
return ERR_NET_SOCKET;
}
// Connect
if ( connect(m_Socket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
// EINPROGRESS always appears on Non Blocking connect
if ( errno != EINPROGRESS )
{
m_connectionStatus = STATUS_CLOSED;
return ERR_NET_SOCKET;
}
// Create a set of sockets for select
fd_set socks;
FD_ZERO(&socks);
FD_SET(m_Socket,&socks);
// Wait for connection or timeout
int fdcnt = select(m_Socket+1,NULL,&socks,NULL,&timeouts);
if ( fdcnt < 0 )
{
return ERR_NET_SOCKET;
}
else if ( fdcnt == 0 )
{
return ERR_TIMEOUT;
}
}
//Set Socket to Blocking again
if(fcntl(m_Socket,F_SETFL,opts_blocking)<0)
{
return ERR_NET_SOCKET;
}
m_connectionStatus = STATUS_OPEN;
return x2e::OK;
如果我用这个功能,我仍然可以连接实际控制并与之通信。但是,如果我用我的TESTSERVER我只是无法连接,选择刚才叶的返回值为0。
所以现在有人会说,我的TESTSERVER是行不通的....但如果我使用阻塞connect()调用,我可以发到我TESTSERVER没有任何问题......
也许有人有一个想法,我可以做什么...?
If I use this function I can still connect on the real controller and communicate with it. But if I use my testserver I just can't connect, select just leaves with a return value of 0. So now someone may say that my testserver just doesn't work....but If I use a blocking connect() call I can send to my testserver without any problems... Maybe someone has an idea what I could do...?
推荐答案
与非阻塞套接字connect()的调用可能与连接返回0,仍然没有准备好
在connect()code部分,可以写成这样(我的连接wraper code段从Python实现教训):
with nonblocking socket connect() call may return 0 with the connection is still not ready the connect() code section, may be written like this(my connect wraper code segment learnt from the python implementation):
if (FAIL_CHECK(connect(sock, (struct sockaddr *) &channel, sizeof(channel)) &&
errno != EINPROGRESS))
{
gko_log(WARNING, "connect error");
ret = HOST_DOWN_FAIL;
goto CONNECT_END;
}
/** Wait for write bit to be set **/
#if HAVE_POLL
{
struct pollfd pollfd;
pollfd.fd = sock;
pollfd.events = POLLOUT;
/* send_sec is in seconds, timeout in ms */
select_ret = poll(&pollfd, 1, (int)(send_sec * 1000 + 1));
}
#else
{
FD_ZERO(&wset);
FD_SET(sock, &wset);
select_ret = select(sock + 1, 0, &wset, 0, &send_timeout);
}
#endif /* HAVE_POLL */
if (select_ret < 0)
{
gko_log(FATAL, "select/poll error on connect");
ret = HOST_DOWN_FAIL;
goto CONNECT_END;
}
if (!select_ret)
{
gko_log(FATAL, "connect timeout on connect");
ret = HOST_DOWN_FAIL;
goto CONNECT_END;
}
Python版本code段:
python version code segment:
res = connect(s->sock_fd, addr, addrlen);
if (s->sock_timeout > 0.0) {
if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {
timeout = internal_select(s, 1);
if (timeout == 0) {
/* Bug #1019808: in case of an EINPROGRESS,
use getsockopt(SO_ERROR) to get the real
error. */
socklen_t res_size = sizeof res;
(void)getsockopt(s->sock_fd, SOL_SOCKET,
SO_ERROR, &res, &res_size);
if (res == EISCONN)
res = 0;
errno = res;
}
else if (timeout == -1) {
res = errno; /* had error */
}
else
res = EWOULDBLOCK; /* timed out */
}
}
if (res < 0)
res = errno;
这篇关于Linux的TCP连接与选择()在TESTSERVER失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!