由于网上大部分教程为阻塞方式连接,当项目需要大量连接从机的情况下,阻塞式连接socket会导致长时间卡顿。因此需要用非阻塞式的方式连接,并设置超时是时间,再设置会阻塞。下属C++编辑代码实测可用,代码如下:
SOCKET s;
ctx->s为 socket的套接字,自己定义即可
int rc;
struct sockaddr_in addr;
modbus_tcp_t *ctx_tcp = ctx->backend_data;
#ifdef OS_WIN32
if (_modbus_tcp_init_win32() == -1) {
return -1;
}
#endif
ctx->s = socket(PF_INET, SOCK_STREAM, 0);
if (ctx->s == -1) {
return -1;
}
rc = setsockopt(ctx->s, IPPROTO_TCP, TCP_NODELAY,
(const void *)&option, sizeof(int));
if (rc == -1) {
return -1;
}
if (ctx->debug) {
printf("Connecting to %s\n", ctx_tcp->ip);
}
//想办法将链接设置为非阻塞,链接完成后再设置为阻塞 william 0924
unsigned long ul = 1;
rc = ioctlsocket(ctx->s, FIONBIO, (unsigned long*)&ul);
if (rc == SOCKET_ERROR)
return -1;
//bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(ctx_tcp->port);
addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip);
rc = connect(ctx->s, (struct sockaddr *)&addr,
sizeof(struct sockaddr_in));
TIMEVAL tm = { 1,0 };//设置超时时间1s
fd_set rset;
fd_set wset;
unsigned long mode = 1;
//一般非锁定模式套接比较难控制,可以根据实际情况考虑 再设回阻塞模式 william 0924
if (rc)
{
rc = WSAGetLastError();
if (WSAEWOULDBLOCK == rc)/*!<如果Resource temporarily unavailable.10035*/
{
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_SET(ctx->s, &rset);
FD_SET(ctx->s, &wset);
rc = select(ctx->s + 1, &rset, &wset, NULL, &tm);
if (rc<0)
{
close(ctx->s);
return -1;
}
else if (rc == 0)/*!<Time Out*/
{
close(ctx->s);
return -1;
}
else
{
if (FD_ISSET(ctx->s, &wset))/*!<如果可写,说明连接好*/
{
mode = 0;
rc = ioctlsocket(ctx->s, FIONBIO, &mode); /*!<再次设置为阻塞模式 */
if (rc)
{
close(ctx->s);
return -1;
}
///*!<正确退出*/
return 0;
}
else
{
// /*!<不可写*/
close(ctx->s);
return -1;
}
}
}// end if(WSAEWOULDBLOCK==ret)
else
{
// /*!<网络出现其他错误*/
close(ctx->s);
return -1;
}
}
else
{
return 0;
}
//一般非锁定模式套接比较难控制,可以根据实际情况考虑 再设回阻塞模式
return 0;