Socket建立连接的问题

lookupheaven 2014-07-21 05:24:53
我用select模型创建了两个非阻塞套接字,试图连接局域网中两台机器A和B,地址分别为192.163.35.140、192.163.35.179。
程序如下:
#include <string>
#include <stdio.h>
#include <WinSock2.h>

#pragma comment(lib, "WS2_32")

void SockSelect(const char* strIP, unsigned short port);

int main()
{
WSAData wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != NO_ERROR)
{
return 0;
}

SockSelect("192.163.35.140", 1234);
SockSelect("192.163.35.179", 1234);

system("pause");
return 0;
}

void SockSelect(const char* strIP, unsigned short port)
{
int error = -1;
int len = sizeof(int);
unsigned long ul = 1;

timeval tm = {20, 0};

SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
printf("falied to create socket.\n");
return ;
}

struct sockaddr_in sockserver;
memset(&sockserver, 0, sizeof(struct sockaddr_in));
sockserver.sin_family = AF_INET;
sockserver.sin_addr.s_addr = inet_addr(strIP);
sockserver.sin_port = htons(1234);

ioctlsocket(sock, FIONBIO, &ul);
fd_set set;
if (connect(sock, (const sockaddr*)&sockserver, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
{
FD_ZERO(&set);
error = WSAGetLastError();
if (error == WSAEWOULDBLOCK)
{
FD_SET(sock, &set);
if(select(0, NULL, &set, NULL, &tm) > 0)
{
getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
if (error == 0)
{
printf("server: %s connected.\n", strIP);
}
}
else
{
error = WSAGetLastError();
printf("error: %d\n", error);
}
}
}
else
{
printf("server: %s connected.\n", strIP);
}
closesocket(sock);
}

第一次运行时,两天机器都能成功连接,但是第二次、第三次。。。第N次连接时,会出现只有A或者B能连接的情况。
我发现,当只连接一台主机时,反复运行都能成功,但是如果两台主机同时连接,那么第一次运行会成功连接两台主机,但是再次运行往往是第一台主机会失败,尤其是,这个结果会随着select超时时间而变化。而且连接失败的时候,WSAGetLastError()函数返回值居然为0。
求教原因,以及如何改进,方能使select超时时间较小,且每次运行都能连接成功。
...全文
583 43 打赏 收藏 转发到动态 举报
写回复
用AI写文章
43 条回复
切换为时间正序
请发表友善的回复…
发表回复
lookupheaven 2014-07-28
  • 打赏
  • 举报
回复
多谢以上诸位,最终的原因终于找到了,是因为我的工具的所有的模块,这边的同事写入的模块MAC地址是相同的,才导致这个问题的出现,链路层的原理我不懂,以后再学习吧
lookupheaven 2014-07-24
  • 打赏
  • 举报
回复
引用 38 楼 besterector 的回复:
[quote=引用 37 楼 zhao4zhong1 的回复:] [quote=引用 25 楼 u010211892 的回复:] 我对赵老师敬仰有如滔滔江水...
[/quote] 我也是~ 赵老师, 麻烦求教个问题。 现在有这么个需求,x86、Win7环境下, 要我能够在1s内,一台普通机器上,最大限度的提高 socket 收发速度, 我目前只能做到5000。 我使用过 非阻塞io(听说效率最高),发现自己不是太懂,无法控制。后来使用多线程的 阻塞io, 可是无法提高线程总数(使用wait函数去同步, 但是wait只能作用于64个一下的线程)。。 现在用 io completion (传说中的iocp), 但是不知道自己的方向对不对。。问了几个同事, 他们都没什么比较好的办法。 求赵老师指点下。。。。。 [/quote] 目测此方向没错
besterector 2014-07-24
  • 打赏
  • 举报
回复
引用 40 楼 Razor87 的回复:
[quote=引用 36 楼 besterector 的回复:] 老兄 写服务器 程序可以尝试下 completion io 。 相对简单(注只是相对)。 我最近也在用。有空一起交流。
iocp倒用不到,我现在找到一个问题,在四次断开的时候,服务端收到FIN包没有发送ACK包,直接就给客户端发FIN包了,不知道是不是这个原因[/quote] closesocket 强制关闭socket,应该是造成你说的现象的直接原因。但是未必是你的问题的答案。
lookupheaven 2014-07-24
  • 打赏
  • 举报
回复
引用 36 楼 besterector 的回复:
老兄 写服务器 程序可以尝试下 completion io 。 相对简单(注只是相对)。 我最近也在用。有空一起交流。
iocp倒用不到,我现在找到一个问题,在四次断开的时候,服务端收到FIN包没有发送ACK包,直接就给客户端发FIN包了,不知道是不是这个原因
besterector 2014-07-24
  • 打赏
  • 举报
回复
我这个问题,另开个帖子吧。
besterector 2014-07-24
  • 打赏
  • 举报
回复
引用 37 楼 zhao4zhong1 的回复:
[quote=引用 25 楼 u010211892 的回复:] 我对赵老师敬仰有如滔滔江水...
[/quote] 我也是~ 赵老师, 麻烦求教个问题。 现在有这么个需求,x86、Win7环境下, 要我能够在1s内,一台普通机器上,最大限度的提高 socket 收发速度, 我目前只能做到5000。 我使用过 非阻塞io(听说效率最高),发现自己不是太懂,无法控制。后来使用多线程的 阻塞io, 可是无法提高线程总数(使用wait函数去同步, 但是wait只能作用于64个一下的线程)。。 现在用 io completion (传说中的iocp), 但是不知道自己的方向对不对。。问了几个同事, 他们都没什么比较好的办法。 求赵老师指点下。。。。。
赵4老师 2014-07-24
  • 打赏
  • 举报
回复
引用 25 楼 u010211892 的回复:
我对赵老师敬仰有如滔滔江水...
besterector 2014-07-24
  • 打赏
  • 举报
回复
老兄 写服务器 程序可以尝试下 completion io 。 相对简单(注只是相对)。 我最近也在用。有空一起交流。
besterector 2014-07-24
  • 打赏
  • 举报
回复
引用 33 楼 Razor87 的回复:
[quote=引用 32 楼 kingstarer 的回复:] [quote=引用 30 楼 Razor87 的回复:] [quote=引用 29 楼 robertbo 的回复:] 用这两个设置超时时间呢 int timeout = 30; setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(int)); setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(int));
我不用select的时候就用这个函数,设的是3000,感觉4、5s才返回,另外刚确定不是路由器交换机的问题[/quote] 服务器代码是什么样的? 是否可以考虑用telnet测试?[/quote] 已经排除是服务器的原因了 我正在抓包分析中[/quote] 这里的timeout 是针对 closesocket 等少数函数的, 对 recv 没用,书上讲的,并且经过亲自验证。
besterector 2014-07-24
  • 打赏
  • 举报
回复
楼主,你确定你的程序运行结果正确吗? 你写的是服务器程序,select 应该 把socket 放在 readfds(第二个)参数里面吧? 还有,应该使用 FD_ISSET 去判断是否 select 对 传入的socket 发生了作用。 还有,select 的读写状态 是被 recv accept 使能的,也就是说, 每次缓存中有数据才能激发select起作用。 最后,如果使用非阻塞socket, 赶脚select 使用起来没啥意义——当然, 我没在非阻塞io上用过,这个观点未必权威。 而且现在让我用我也不会。。。。。
kingstarer 2014-07-23
  • 打赏
  • 举报
回复
引用 30 楼 Razor87 的回复:
[quote=引用 29 楼 robertbo 的回复:] 用这两个设置超时时间呢 int timeout = 30; setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(int)); setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(int));
我不用select的时候就用这个函数,设的是3000,感觉4、5s才返回,另外刚确定不是路由器交换机的问题[/quote] 服务器代码是什么样的? 是否可以考虑用telnet测试?
mujiok2003 2014-07-23
  • 打赏
  • 举报
回复
引用 27 楼 Razor87 的回复:
[quote=引用 23 楼 mujiok2003 的回复:] [quote=引用 13 楼 Razor87 的回复:] [quote=引用 9 楼 mujiok2003 的回复:] select返回0表明time out

int a = select(.....);
if(a > 0 ) {
 //connected
}
else if (a ==0){
   //time out, retry?
}
else
{
  //error here
}
症状就是有时候a == 0,有时候a > 0,不够稳定[/quote] 追求稳定没有意义,因为连接建立所需要的时间不是固定的。 [/quote] 我现在要检测多个服务器模块的连接情况,socket超时时间不能过长,而且,这个代码就算把超时时间设成1分钟,都会出现这种情况,郁闷[/quote] 自己统计开始发起连接到连接成功的时间即可, 跟超时没有关系。
lookupheaven 2014-07-23
  • 打赏
  • 举报
回复
引用 29 楼 robertbo 的回复:
用这两个设置超时时间呢 int timeout = 30; setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(int)); setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(int));
我不用select的时候就用这个函数,设的是3000,感觉4、5s才返回,另外刚确定不是路由器交换机的问题
robertbo 2014-07-23
  • 打赏
  • 举报
回复
用这两个设置超时时间呢 int timeout = 30; setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(int)); setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(int));
lookupheaven 2014-07-23
  • 打赏
  • 举报
回复
引用 24 楼 kingstarer 的回复:
为啥要select啊,直接recv不行吗
阻塞socket的连接时间太长了
lookupheaven 2014-07-23
  • 打赏
  • 举报
回复
引用 23 楼 mujiok2003 的回复:
[quote=引用 13 楼 Razor87 的回复:] [quote=引用 9 楼 mujiok2003 的回复:] select返回0表明time out

int a = select(.....);
if(a > 0 ) {
 //connected
}
else if (a ==0){
   //time out, retry?
}
else
{
  //error here
}
症状就是有时候a == 0,有时候a > 0,不够稳定[/quote] 追求稳定没有意义,因为连接建立所需要的时间不是固定的。 [/quote] 我现在要检测多个服务器模块的连接情况,socket超时时间不能过长,而且,这个代码就算把超时时间设成1分钟,都会出现这种情况,郁闷
lookupheaven 2014-07-23
  • 打赏
  • 举报
回复
引用 18 楼 robertbo 的回复:
[quote=引用 16 楼 Razor87 的回复:] [quote=引用 15 楼 robertbo 的回复:] WSAStartup一次,socket调用两次,把SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);调整到函数外面,作为参数传进去,调用结束后释放,然后再调用WSAStartup和sock = socket试试呢。
依然如故,莫非真是服务端的问题? 另外,再问一下大牛,正常TCP连接socket,如果服务端和客户端都正常,会不会存在这种两个socket重复连接时有一个连不上的情况?[/quote] 没遇到过哦,给你发的都是我以前做过的程序摘出来的,是可以正常连接和断开的。连接的时候服务器是什么反应,有日志记录吗?[/quote] 没有日志,这个环境中有多个单独的服务器模块,我现在怀疑是不是网络配置的问题了,我先找个单独的路由器试试
lookupheaven 2014-07-23
  • 打赏
  • 举报
回复
引用 32 楼 kingstarer 的回复:
[quote=引用 30 楼 Razor87 的回复:] [quote=引用 29 楼 robertbo 的回复:] 用这两个设置超时时间呢 int timeout = 30; setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(int)); setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(int));
我不用select的时候就用这个函数,设的是3000,感觉4、5s才返回,另外刚确定不是路由器交换机的问题[/quote] 服务器代码是什么样的? 是否可以考虑用telnet测试?[/quote] 已经排除是服务器的原因了 我正在抓包分析中
robertbo 2014-07-22
  • 打赏
  • 举报
回复
WSAStartup一次,socket调用两次,把SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);调整到函数外面,作为参数传进去,调用结束后释放,然后再调用WSAStartup和sock = socket试试呢。
lookupheaven 2014-07-22
  • 打赏
  • 举报
回复
引用 11 楼 zhao4zhong1 的回复:
检查是否资源泄漏的办法之一: 在任务管理器 进程 查看 选择列 里面选择:内存使用、虚拟内存大小、句柄数、线程数、USER对象、GDI对象 让你的程序(进程)不退出,循环执行主流程很多遍,越多越好,比如1000000次甚至无限循环,记录以上各数值,再隔至少一小时,越长越好,比如一个月,再记录以上各数值。如果以上两组数值的差较大或随时间流逝不断增加,则铁定有对应资源的资源泄漏!
赵老师明言,这个程序有个问题就是没调用WSACleanup释放winsock库,不过改正后问题仍然存在,上述代码就是整个程序了,应与资源泄露无关。
加载更多回复(22)

64,684

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧