一个Socket问题(高手请进)---郁闷而死 对不起,是select后返回为超时 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 应该是这样。Server端:WSAStartup -> socket -> bind -> listen -> WSAAsyncSelect -> accept;accept成功才算是真正的连通。Client端:WSAStartup -> socket -> connect -> WSAAsyncSelect;客户端必须调用connect请求连接。 TopLevel(),你进了一个误区,真正正确的用法是Server端:WSAStartup -> socket -> bind -> listen -> accept -> WSAAsyncSelect;Client端:WSAStartup -> socket -> WSAAsyncSelect -> connect;why? 很简单,避免在accept/connect 与 WSAAsyncSelect的时间间隔之内丢失FD_CONNECT/FD_ACCEPT时间! TopLevel(),你进了一个误区,真正正确的用法是Server端:WSAStartup -> socket -> bind -> listen -> accept -> WSAAsyncSelect;Client端:WSAStartup -> socket -> WSAAsyncSelect -> connect;why? 很简单,避免在accept/connect 与 WSAAsyncSelect的时间间隔之内丢失FD_CONNECT/FD_ACCEPT时间! 对不起,没看很清楚Server端:WSAStartup -> socket -> bind -> listen -> WSAAsyncSelect -> accept;Client端:WSAStartup -> socket -> WSAAsyncSelect -> connect; To solar,看看MSDN下的例子。globchat 对不起,没看很清楚Server端:WSAStartup -> socket -> bind -> listen -> accept -> WSAAsyncSelect;Client端:WSAStartup -> socket -> connect -> WSAAsyncSelect; 搞反了。应该是Server端:WSAStartup -> socket -> bind -> listen -> WSAAsyncSelect -> accept;Client端:WSAStartup -> socket -> WSAAsyncSelect -> connect; 搞反了。应该是Server端:WSAStartup -> socket -> bind -> listen -> WSAAsyncSelect -> accept;Client端:WSAStartup -> socket -> WSAAsyncSelect -> connect; Server端:WSAStartup -> socket -> (bind) -> WSAAsyncSelect -> listen -> accept;Client端:WSAStartup -> socket -> (bind) -> WSAAsyncSelect -> connect; 〉client经过connect后总是返回连接失败WSAWOULDDBLOCK这是正常现象,正是异步的含义,connect成功(或失败)后会发送FD_CONNECT事件〉我不理解的疑问:server在accept时接收到的客户sockaddr的sin_port不等于客户端connect时服务器的sin_port客户sockaddr的sin_port与服务器的sin_port是两回事,进行TCP通讯的两端C/S每端都有一个端口,Server端的端口是通过bind绑定的,而客户端的端口则是由OS或者TCP层随机分配的 我不理解的疑问:server在accept时接收到的客户sockaddr的sin_port不等于 客户端connect时服务器的sin_port,我知道这都是网络字节顺序的, 初始我都设为10000.为什么不相等?对于以上疑问,因为server在accept时系统自动创建一个套接字描述符,对应于几经接受的那个客户机连接,对于该客户机后续的所有操作,都应该使用这个套接字,原来的那个监听套接字,仍然用于接受其他客户机的连接,而且仍处于监听模式 wxzfox(乐乐)说的对,我一时糊涂了 > wxzfox(乐乐)说的对,我一时糊涂了指的是上面关于WSAAsyncSelect调用时机的问题 WSAAsyncSelect应该放在前面再去accept或connect,否则怎么触发事件!有没有别的可能?(winsock2.h和ws2_32.lib)为什么sin_port会不同? solar(int argc,char**argv) :wxzfox(乐乐)说的对,我也一时胡涂了。我的client 非阻塞 connect时收到WSAWOULDDBLOCK属于正常情况,但是这么解决这个问题,select()后超时错误。FD_CONNECT : WSAGETSELECTERROR(lParam)错误。 因为server在accept时系统自动创建一个套接字描述符,对应于已经接受的那个客户机连接,对于该客户机后续的所有操作,都应该使用这个套接字,原来的那个监听套接字,仍然用于接受其他客户机的连接,而且仍处于监听模式。就是说ACCEPT函数得到的SOCKET是服务器在服务端建立的,与客户端的SOCKET无关,它们之间已经建立起虚电路连接,ADDRESS和PORT就可以忽略了 void main(void){ MSG msg; DWORD Ret; SOCKET Listen; SOCKADDR_IN InternetAddr; HWND Window; WSADATA wsaData; if ((Window = MakeWorkerWindow()) == NULL) return; // Prepare echo server if ((Ret = WSAStartup(0x0202, &wsaData)) != 0) { printf("WSAStartup failed with error %d\n", Ret); return; } if ((Listen = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { printf("socket() failed with error %d\n", WSAGetLastError()); return; } WSAAsyncSelect(Listen, Window, WM_SOCKET, FD_ACCEPT|FD_CLOSE); InternetAddr.sin_family = AF_INET; InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY); InternetAddr.sin_port = htons(PORT); if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR) { printf("bind() failed with error %d\n", WSAGetLastError()); return; } if (listen(Listen, 5)) { printf("listen() failed with error %d\n", WSAGetLastError()); return; } // Translate and dispatch window messages for the application thread while(Ret = GetMessage(&msg, NULL, 0, 0)) { if (Ret == -1) { printf("GetMessage() failed with error %d\n", GetLastError()); return; } TranslateMessage(&msg); DispatchMessage(&msg); }}LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ SOCKET Accept; LPSOCKET_INFORMATION SocketInfo; DWORD RecvBytes, SendBytes; DWORD Flags; if (uMsg == WM_SOCKET) { if (WSAGETSELECTERROR(lParam)) { printf("Socket failed with error %d\n", WSAGETSELECTERROR(lParam)); FreeSocketInformation(wParam); } else { switch(WSAGETSELECTEVENT(lParam)) { case FD_ACCEPT: if ((Accept = accept(wParam, NULL, NULL)) == INVALID_SOCKET) { printf("accept() failed with error %d\n", WSAGetLastError()); break; } // Create a socket information structure to associate with the // socket for processing I/O. CreateSocketInformation(Accept); printf("Socket number %d connected\n", Accept); WSAAsyncSelect(Accept, hwnd, WM_SOCKET, FD_READ|FD_WRITE|FD_CLOSE); break; case FD_READ: SocketInfo = GetSocketInformation(wParam); // Read data only if the receive buffer is empty. if (SocketInfo->BytesRECV != 0) { SocketInfo->RecvPosted = TRUE; return 0; } else { SocketInfo->DataBuf.buf = SocketInfo->Buffer; SocketInfo->DataBuf.len = DATA_BUFSIZE; Flags = 0; if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes, &Flags, NULL, NULL) == SOCKET_ERROR) { if (WSAGetLastError() != WSAEWOULDBLOCK) { printf("WSARecv() failed with error %d\n", WSAGetLastError()); FreeSocketInformation(wParam); return 0; } } else // No error so update the byte count { SocketInfo->BytesRECV = RecvBytes; } } // DO NOT BREAK HERE SINCE WE GOT A SUCCESSFUL RECV. Go ahead // and begin writing data to the client. case FD_WRITE: SocketInfo = GetSocketInformation(wParam); if (SocketInfo->BytesRECV > SocketInfo->BytesSEND) { SocketInfo->DataBuf.buf = SocketInfo->Buffer + SocketInfo->BytesSEND; SocketInfo->DataBuf.len = SocketInfo->BytesRECV - SocketInfo->BytesSEND; if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &SendBytes, 0, NULL, NULL) == SOCKET_ERROR) { if (WSAGetLastError() != WSAEWOULDBLOCK) { printf("WSASend() failed with error %d\n", WSAGetLastError()); FreeSocketInformation(wParam); return 0; } } else // No error so update the byte count { SocketInfo->BytesSEND += SendBytes; } } if (SocketInfo->BytesSEND == SocketInfo->BytesRECV) { SocketInfo->BytesSEND = 0; SocketInfo->BytesRECV = 0; // If a RECV occurred during our SENDs then we need to post an FD_READ // notification on the socket. if (SocketInfo->RecvPosted == TRUE) { SocketInfo->RecvPosted = FALSE; PostMessage(hwnd, WM_SOCKET, wParam, FD_READ); } } break; case FD_CLOSE: printf("Closing socket %d\n", wParam); FreeSocketInformation(wParam); break; } } return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam);} 〉因为server在accept时系统自动创建一个套接字描述符,对应于已经接受的那个客户机连接,对于该客户机后续的所有操作,都应该使用这个套接字,原来的那个监听套接字,仍然用于接受其他客户机的连接,而且仍处于监听模式。就是说ACCEPT函数得到的SOCKET是服务器在服务端建立的,与客户端的SOCKET无关,它们之间已经建立起虚电路连接,ADDRESS和PORT就可以忽略了不是这样的,accept得到的sock_addr结构中的端口是客户端socket的端口,客户端socket的端口是由系统分配的;虽然accept确实创建了一个新的socket与客户端通讯,但这个新的socket的端口与listen的socket的端口是一样的(可以用getsockname看看) wxzfox(乐乐) 我不是要例程啊,我想是阻塞和非阻塞问题。wxzfox(乐乐) 从那儿超过来的,里边有错误! 不会吧,我从《windows网络编程技术》的源代码中弄来的,应该没有问题 《windows网络编程技术》的源程序,应该没有问题 寻求一个方法 vs2010 CTabView VC中怎样设置子对话框的图标? 求助串口发送初始化的问题 上班时间被老板发现在用QQ 超级高手进来看!!!!!!!!!!! 基于对话框的程序,没有错误,可是运行后对话框不显示 [20分]在线等:公司主页就放在服务器上,可服务器每次只有重启后才能正常访问,而且过了两到三个小时又不行了!帮帮我 如何由VB传递参数到VC中显示~~~急急急 求助,怎么样使程序运行最小化时压缩在右下角形成一图标? COM中char类型的如何通信啊? 使用CRecordset派生类时无法添加大于256字节的数据?
Server端:
WSAStartup -> socket -> bind -> listen -> WSAAsyncSelect -> accept;
accept成功才算是真正的连通。
Client端:
WSAStartup -> socket -> connect -> WSAAsyncSelect;
客户端必须调用connect请求连接。
WSAStartup -> socket -> bind -> listen -> accept -> WSAAsyncSelect;
Client端:
WSAStartup -> socket -> WSAAsyncSelect -> connect;why? 很简单,避免在accept/connect 与 WSAAsyncSelect的时间间隔之内丢失FD_CONNECT/FD_ACCEPT时间!
WSAStartup -> socket -> bind -> listen -> accept -> WSAAsyncSelect;
Client端:
WSAStartup -> socket -> WSAAsyncSelect -> connect;why? 很简单,避免在accept/connect 与 WSAAsyncSelect的时间间隔之内丢失FD_CONNECT/FD_ACCEPT时间!
WSAStartup -> socket -> bind -> listen -> WSAAsyncSelect -> accept;
Client端:
WSAStartup -> socket -> WSAAsyncSelect -> connect;
看看MSDN下的例子。globchat
WSAStartup -> socket -> bind -> listen -> accept -> WSAAsyncSelect;
Client端:
WSAStartup -> socket -> connect -> WSAAsyncSelect;
WSAStartup -> socket -> bind -> listen -> WSAAsyncSelect -> accept;
Client端:
WSAStartup -> socket -> WSAAsyncSelect -> connect;
WSAStartup -> socket -> bind -> listen -> WSAAsyncSelect -> accept;
Client端:
WSAStartup -> socket -> WSAAsyncSelect -> connect;
WSAStartup -> socket -> (bind) -> WSAAsyncSelect -> listen -> accept;
Client端:
WSAStartup -> socket -> (bind) -> WSAAsyncSelect -> connect;
这是正常现象,正是异步的含义,connect成功(或失败)后会发送FD_CONNECT事件〉我不理解的疑问:server在accept时接收到的客户sockaddr的sin_port不等于客户端connect时服务器的sin_port
客户sockaddr的sin_port与服务器的sin_port是两回事,进行TCP通讯的两端C/S每端都有一个端口,Server端的端口是通过bind绑定的,而客户端的端口则是由OS或者TCP层随机分配的
客户端connect时服务器的sin_port,我知道这都是网络字节顺序的,
初始我都设为10000.为什么不相等?对于以上疑问,因为server在accept时系统自动创建一个套接字描述符,对应于几经接受的那个客户机连接,对于该客户机后续的所有操作,都应该使用这个套接字,原来的那个监听套接字,仍然用于接受其他客户机的连接,而且仍处于监听模式
指的是上面关于WSAAsyncSelect调用时机的问题
wxzfox(乐乐)说的对,我也一时胡涂了。
我的client 非阻塞 connect时收到WSAWOULDDBLOCK属于正常情况,
但是这么解决这个问题,select()后超时错误。
FD_CONNECT : WSAGETSELECTERROR(lParam)错误。
{
MSG msg;
DWORD Ret;
SOCKET Listen;
SOCKADDR_IN InternetAddr;
HWND Window;
WSADATA wsaData; if ((Window = MakeWorkerWindow()) == NULL)
return; // Prepare echo server if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
{
printf("WSAStartup failed with error %d\n", Ret);
return;
} if ((Listen = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
printf("socket() failed with error %d\n", WSAGetLastError());
return;
} WSAAsyncSelect(Listen, Window, WM_SOCKET, FD_ACCEPT|FD_CLOSE); InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT); if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
printf("bind() failed with error %d\n", WSAGetLastError());
return;
} if (listen(Listen, 5))
{
printf("listen() failed with error %d\n", WSAGetLastError());
return;
}
// Translate and dispatch window messages for the application thread while(Ret = GetMessage(&msg, NULL, 0, 0))
{
if (Ret == -1)
{
printf("GetMessage() failed with error %d\n", GetLastError());
return;
} TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SOCKET Accept;
LPSOCKET_INFORMATION SocketInfo;
DWORD RecvBytes, SendBytes;
DWORD Flags; if (uMsg == WM_SOCKET)
{
if (WSAGETSELECTERROR(lParam))
{
printf("Socket failed with error %d\n", WSAGETSELECTERROR(lParam));
FreeSocketInformation(wParam);
}
else
{
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT: if ((Accept = accept(wParam, NULL, NULL)) == INVALID_SOCKET)
{
printf("accept() failed with error %d\n", WSAGetLastError());
break;
} // Create a socket information structure to associate with the
// socket for processing I/O. CreateSocketInformation(Accept); printf("Socket number %d connected\n", Accept); WSAAsyncSelect(Accept, hwnd, WM_SOCKET, FD_READ|FD_WRITE|FD_CLOSE); break; case FD_READ: SocketInfo = GetSocketInformation(wParam); // Read data only if the receive buffer is empty. if (SocketInfo->BytesRECV != 0)
{
SocketInfo->RecvPosted = TRUE;
return 0;
}
else
{
SocketInfo->DataBuf.buf = SocketInfo->Buffer;
SocketInfo->DataBuf.len = DATA_BUFSIZE; Flags = 0;
if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes,
&Flags, NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
FreeSocketInformation(wParam);
return 0;
}
}
else // No error so update the byte count
{
SocketInfo->BytesRECV = RecvBytes;
}
} // DO NOT BREAK HERE SINCE WE GOT A SUCCESSFUL RECV. Go ahead
// and begin writing data to the client. case FD_WRITE: SocketInfo = GetSocketInformation(wParam); if (SocketInfo->BytesRECV > SocketInfo->BytesSEND)
{
SocketInfo->DataBuf.buf = SocketInfo->Buffer + SocketInfo->BytesSEND;
SocketInfo->DataBuf.len = SocketInfo->BytesRECV - SocketInfo->BytesSEND; if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &SendBytes, 0,
NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("WSASend() failed with error %d\n", WSAGetLastError());
FreeSocketInformation(wParam);
return 0;
}
}
else // No error so update the byte count
{
SocketInfo->BytesSEND += SendBytes;
}
} if (SocketInfo->BytesSEND == SocketInfo->BytesRECV)
{
SocketInfo->BytesSEND = 0;
SocketInfo->BytesRECV = 0; // If a RECV occurred during our SENDs then we need to post an FD_READ
// notification on the socket. if (SocketInfo->RecvPosted == TRUE)
{
SocketInfo->RecvPosted = FALSE;
PostMessage(hwnd, WM_SOCKET, wParam, FD_READ);
}
} break; case FD_CLOSE: printf("Closing socket %d\n", wParam);
FreeSocketInformation(wParam); break;
}
}
return 0;
} return DefWindowProc(hwnd, uMsg, wParam, lParam);
}