Windows ConnectEx要求插座为;最初绑定的“;,但是为了什么?
该函数需要一个“未连接、先前绑定的套接字”。事实上,如果我在我的示例中省略了这个步骤(见下文),那么将失败 以下是我目前的理解:在调用之前,将套接字连接到Windows ConnectEx要求插座为;最初绑定的“;,但是为了什么?,windows,network-programming,winsock,overlapped-io,Windows,Network Programming,Winsock,Overlapped Io,该函数需要一个“未连接、先前绑定的套接字”。事实上,如果我在我的示例中省略了这个步骤(见下文),那么将失败 以下是我目前的理解:在调用之前,将套接字连接到INADDR\u ANY和端口0(除非已经绑定): 或对于IPv6套接字: struct sockaddr_in6 addr; ZeroMemory(&addr, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = in6addr_any; addr.sin6_por
INADDR\u ANY
和端口0(除非已经绑定):
或对于IPv6套接字:
struct sockaddr_in6 addr;
ZeroMemory(&addr, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr = in6addr_any;
addr.sin6_port = 0;
rc = bind(sock, (SOCKADDR*) &addr, sizeof(addr));
if (rc != 0) { ... bind failed; call WSAGetLastError to see why ... }
这允许操作系统为我们的套接字分配一个本地地址(与我们连接的远程地址相反)。自动执行此步骤,但不执行
我的问题是:
AF_INET
、AF_INET6
、AF_BTH
(蓝牙)等#包括
#包括
#包括
#包括
#pragma注释(lib,“Ws2_32.lib”)
结构mswsock\u s{
LPFN_CONNECTEX CONNECTEX;
}mswsock;
静态BOOL load_mswsock(无效)
{
插座;
双字双字节;
int rc;
/*WSAIoctl需要虚拟套接字*/
sock=socket(AF\u INET,sock\u STREAM,0);
if(sock==无效的_套接字)
返回FALSE;
{
GUID=WSAID_CONNECTEX;
rc=WSAIoctl(sock,SIO_GET_EXTENSION_函数_指针,
&guid,sizeof(guid),
&mswsock.ConnectEx,sizeof(mswsock.ConnectEx),
&dwBytes,NULL,NULL);
如果(rc!=0)
返回FALSE;
}
rc=闭合插座(插座);
如果(rc!=0)
返回FALSE;
返回TRUE;
}
int main(int argc,char*argv[])
{
int rc;
布尔ok;
WSADATA WSADATA;
插座;
rc=WSAStartup(MAKEWORD(2,2)和wsaData);
如果(rc!=0){
printf(“WSAStartup失败:%d\n”,rc);
返回1;
}
如果(LOBYTE(wsaData.wVersion)!=2 | | HIBYTE(wsaData.wVersion)!=2){
printf(“您的计算机来自错误的千年。\n”);
WSACleanup();
返回1;
}
如果(!load_mswsock()){
printf(“加载mswsock函数时出错:%d\n”,WSAGetLastError());
返回1;
}
sock=socket(AF\u INET,sock\u STREAM,0);
if(sock==无效的_套接字){
printf(“套接字:%d\n”,WSAGetLastError());
返回1;
}
/*ConnectEx要求最初绑定套接字*/
{
地址中的结构sockaddr\u;
零内存(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin\u addr.s\u addr=INADDR\u ANY;
地址sin_端口=0;
rc=bind(sock,(SOCKADDR*)和addr,sizeof(addr));
如果(rc!=0){
printf(“绑定失败:%d\n”,WSAGetLastError());
返回1;
}
}
/*发出ConnectEx并等待操作完成*/
{
重叠ol;
零内存(&ol,sizeof(ol));
地址中的sockaddr_;
零内存(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=inet_addr(“173.194.37.36”);//google.com
地址sin_端口=htons(80);
ok=mswsock.ConnectEx(sock,(SOCKADDR*)&addr,sizeof(addr),NULL,0,NULL,&ol);
如果(确定){
printf(“ConnectEx立即成功\n”);
}else if(WSAGetLastError()==错误\u IO\u挂起){
printf(“ConnectEx挂起”);
德沃德·努比特斯;
ok=GetOverlappedResult((句柄)sock、&ol、&numBytes,TRUE);
如果(确定)
printf(“ConnectEx成功\n”);
其他的
printf(“ConnectEx失败:%d\n”,WSAGetLastError());
}否则{
printf(“ConnectEx失败:%d\n”,WSAGetLastError());
返回1;
}
}
/*使套接字的性能更好*/
rc=setsockopt(sock,SOL_SOCKET,SO_UPDATE_CONNECT_CONTEXT,NULL,0);
如果(rc!=0){
printf(“SO_更新_连接_上下文失败:%d\n”,WSAGetLastError());
返回1;
}
/*如果未执行SO\u更新\u连接\u上下文,则此操作将失败*/
rc=停机(sock和SD_均为);
如果(rc!=0){
printf(“关闭失败:%d\n”,WSAGetLastError());
返回1;
}
printf(“完成”\n);
返回0;
}
connect会自动执行此步骤,但ConnectEx不会
对
我的评估正确吗
对
有没有一种方法可以实现与地址族无关的自动绑定,或者我必须手动处理AF_INET、AF_INET6、AF_BTH(蓝牙)等
我相信INADDR\u ANY
在所有地址族中都是一堆零,因此您可以尝试使用memset()
并完全忽略对addr.sin\u addr.s\u addr的赋值。这是否符合犹太教、便于携带、政治正确等是另一个我不想讨论的问题
考虑到保存系统调用是其存在的动机,微软没有设法在内部调用ConnectEx()
callbind()
,这似乎很奇怪,同时考虑到大多数程序根本不会绑定出站套接字。可以通过独立于地址族的方式获取ConnectEx的绑定地址
解决方案1
使用以下选项调用getaddrinfo
:
pServiceName = "0"
hints.ai_flags = AI_PASSIVE
hints.ai_family = address family of the socket
然后使用返回的地址列表的第一个结果
要获取套接字的地址族,可以将getsockopt
与SO\u PROTOCOL\u INFOW
一起使用
解决方案2
对地址结构使用SOCKADDR\u存储
,并调用MSTcpIP.h
中定义的INETADDR\u SETANY
。它支持AF\u INET
和AF\u INET6
#include <stdio.h>
#include <WinSock2.h>
#include <MSWSock.h>
#include <WS2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
struct mswsock_s {
LPFN_CONNECTEX ConnectEx;
} mswsock;
static BOOL load_mswsock(void)
{
SOCKET sock;
DWORD dwBytes;
int rc;
/* Dummy socket needed for WSAIoctl */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
return FALSE;
{
GUID guid = WSAID_CONNECTEX;
rc = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid, sizeof(guid),
&mswsock.ConnectEx, sizeof(mswsock.ConnectEx),
&dwBytes, NULL, NULL);
if (rc != 0)
return FALSE;
}
rc = closesocket(sock);
if (rc != 0)
return FALSE;
return TRUE;
}
int main(int argc, char *argv[])
{
int rc;
BOOL ok;
WSADATA wsaData;
SOCKET sock;
rc = WSAStartup(MAKEWORD(2,2), &wsaData);
if (rc != 0) {
printf("WSAStartup failed: %d\n", rc);
return 1;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("Your computer is from the wrong millenium.\n");
WSACleanup();
return 1;
}
if (!load_mswsock()) {
printf("Error loading mswsock functions: %d\n", WSAGetLastError());
return 1;
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
printf("socket: %d\n", WSAGetLastError());
return 1;
}
/* ConnectEx requires the socket to be initially bound. */
{
struct sockaddr_in addr;
ZeroMemory(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = 0;
rc = bind(sock, (SOCKADDR*) &addr, sizeof(addr));
if (rc != 0) {
printf("bind failed: %d\n", WSAGetLastError());
return 1;
}
}
/* Issue ConnectEx and wait for the operation to complete. */
{
OVERLAPPED ol;
ZeroMemory(&ol, sizeof(ol));
sockaddr_in addr;
ZeroMemory(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("173.194.37.36"); // google.com
addr.sin_port = htons(80);
ok = mswsock.ConnectEx(sock, (SOCKADDR*) &addr, sizeof(addr), NULL, 0, NULL, &ol);
if (ok) {
printf("ConnectEx succeeded immediately\n");
} else if (WSAGetLastError() == ERROR_IO_PENDING) {
printf("ConnectEx pending\n");
DWORD numBytes;
ok = GetOverlappedResult((HANDLE) sock, &ol, &numBytes, TRUE);
if (ok)
printf("ConnectEx succeeded\n");
else
printf("ConnectEx failed: %d\n", WSAGetLastError());
} else {
printf("ConnectEx failed: %d\n", WSAGetLastError());
return 1;
}
}
/* Make the socket more well-behaved. */
rc = setsockopt(sock, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
if (rc != 0) {
printf("SO_UPDATE_CONNECT_CONTEXT failed: %d\n", WSAGetLastError());
return 1;
}
/* This will fail if SO_UPDATE_CONNECT_CONTEXT was not performed. */
rc = shutdown(sock, SD_BOTH);
if (rc != 0) {
printf("shutdown failed: %d\n", WSAGetLastError());
return 1;
}
printf("Done\n");
return 0;
}
pServiceName = "0"
hints.ai_flags = AI_PASSIVE
hints.ai_family = address family of the socket