转自出处
getsockname可以获得一个与socket相关的地址。
服务器端可以通过它得到相关客户端地址。
而客户端也可以得到当前已连接成功的socket的ip和端口。
第二种情况在客户端不进行bind而直接连接服务器时,而且客户端需要知道当前使用哪个ip进行通信时比较有用(如多网卡的情况)。
笔者分别通过TCP和UDP协议进行测试,测试结果表明:
对于TCP连接的情况,如果不进行bind指定IP和端口,那么调用connect连接成功后,使用getsockname可以正确获得当前正在通信的socket的IP和端口地址。
而对于UDP的情况,无论是在调用sendto之后还是收到服务器返回的信息之后调用,都无法得到正确的ip地址:使用getsockname得到ip为0,端口正确。
测试用例如下:
1. TCP
//client
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsadata;
int ret = WSAStartup ( 0x0202 , & wsadata );
if ( ret != 0 || 0x0202 != wsadata.wVersion )
{
cout<<"WSAStartup Error!";
return 0;
}
SOCKET mySock = INVALID_SOCKET;
mySock = socket(AF_INET,SOCK_STREAM,0);
if (mySock == INVALID_SOCKET)
{
cout<<"Create Socket Error!";
return 0;
}
sockaddr_in addrDest;
memset(&addrDest,0,sizeof(addrDest));
addrDest.sin_family = AF_INET;
addrDest.sin_addr.s_addr = inet_addr("10.10.44.76");
addrDest.sin_port = htons(9000);
ret = connect(mySock,(sockaddr*)&addrDest,sizeof(addrDest));
if (ret == -1)
{
cout<<GetLastError()<<endl;
return 0;
}
cout<<"Connect to Server Success!"<<endl;
sockaddr_in addrMy;
memset(&addrMy,0,sizeof(addrMy));
int len = sizeof(addrMy);
ret = getsockname(mySock,(sockaddr*)&addrMy,&len);
if (ret != 0)
{
cout<<"Getsockname Error!"<<endl;
return 0;
}
cout<<"Current Socket IP:"<<inet_ntoa(addrMy.sin_addr)<<":"<<ntohs(addrMy.sin_port)<<endl;
getchar();
closesocket(mySock);
WSACleanup();
return 0;
}
//server
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsadata;
int ret = WSAStartup ( 0x0202 , & wsadata );
if ( ret != 0 || 0x0202 != wsadata.wVersion )
{
cout<<"WSAStartup Error!";
return 0;
}
SOCKET listenSock = INVALID_SOCKET;
listenSock = socket(AF_INET,SOCK_STREAM,0);
if (listenSock == INVALID_SOCKET)
{
cout<<"Create Socket Error!";
return 0;
}
sockaddr_in addrBind;
memset(&addrBind,0,sizeof(addrBind));
addrBind.sin_family = AF_INET;
addrBind.sin_addr.s_addr = INADDR_ANY;
addrBind.sin_port = htons(9000);
ret = bind(listenSock,(sockaddr*)&addrBind,sizeof(addrBind));
if (ret == SOCKET_ERROR)
{
cout<<"Bind Error"<<endl;
return 0;
}
ret = listen(listenSock,5);
if (ret != 0)
{
cout<<"Listen Error"<<endl;
return 0;
}
SOCKET conSock;
sockaddr_in addrCon;
int len = sizeof(addrCon);
while (true)
{
conSock = accept(listenSock,(sockaddr*)&addrCon,&len);
if (conSock == INVALID_SOCKET)
{
cout<<"Accept Error"<<endl;
return 0;
}
cout<<inet_ntoa(addrCon.sin_addr)<<" Connect to Server!"<<endl;
}
closesocket(conSock);
closesocket(listenSock);
WSACleanup();
return 0;
}
2. UDP
//client
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsadata;
int ret = WSAStartup ( 0x0202 , & wsadata );
if ( ret != 0 || 0x0202 != wsadata.wVersion )
{
cout<<"WSAStartup Error!";
return 0;
}
SOCKET mySock = INVALID_SOCKET;
mySock = socket(AF_INET,SOCK_DGRAM,0);
if (mySock == INVALID_SOCKET)
{
cout<<"Create Socket Error!";
return 0;
}
sockaddr_in addrDest;
memset(&addrDest,0,sizeof(addrDest));
addrDest.sin_family = AF_INET;
addrDest.sin_addr.s_addr = inet_addr("10.10.44.76");
addrDest.sin_port = htons(9000);
//set non-blocking
int nMode = 1;
ioctlsocket(mySock,FIONBIO,(u_long FAR*) &nMode);
char sendchar[20];
strcpy_s(sendchar,"login");
sendto(mySock,sendchar,strlen(sendchar)+1,0,(sockaddr*)&addrDest,sizeof(sockaddr));
//get send socket ip
sockaddr_in addrMy;
memset(&addrMy,0,sizeof(addrMy));
int leng = sizeof(addrMy);
ret = getsockname(mySock,(sockaddr*)&addrMy,&leng);
if (ret != 0)
{
cout<<"Getsockname Error!"<<endl;
return 0;
}
cout<<"Current Socket IP:"<<inet_ntoa(addrMy.sin_addr)<<":"<<ntohs(addrMy.sin_port)<<endl;
char recvchar[20];
sockaddr_in addrRev;
memset(&addrRev,0,sizeof(addrRev));
memset(recvchar,0,20);
int len = sizeof(sockaddr);
while (true)
{
if (recvfrom(mySock,recvchar,20,0,(sockaddr*)&addrRev,&len) == SOCKET_ERROR)
{
if (GetLastError() == WSAEWOULDBLOCK || GetLastError() == 10054)
{
continue;
}
else
{
cout<<"Receive Error!"<<GetLastError()<<endl;
return 0;
}
}
cout<<"login success!"<<endl;
//get send socket ip
sockaddr_in addrMy;
memset(&addrMy,0,sizeof(addrMy));
int leng = sizeof(addrMy);
ret = getsockname(mySock,(sockaddr*)&addrMy,&leng);
if (ret != 0)
{
cout<<"Getsockname Error!"<<endl;
return 0;
}
cout<<"Current Socket IP:"<<inet_ntoa(addrMy.sin_addr)<<":"<<ntohs(addrMy.sin_port)<<endl;
}
return 0;
}
//server
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsadata;
int ret = WSAStartup ( 0x0202 , & wsadata );
if ( ret != 0 || 0x0202 != wsadata.wVersion )
{
cout<<"WSAStartup Error!";
return 0;
}
SOCKET mySock = INVALID_SOCKET;
mySock = socket(AF_INET,SOCK_DGRAM,0);
if (mySock == INVALID_SOCKET)
{
cout<<"Create Socket Error!";
return 0;
}
sockaddr_in addrBind;
memset(&addrBind,0,sizeof(addrBind));
addrBind.sin_family = AF_INET;
addrBind.sin_addr.s_addr = INADDR_ANY;
addrBind.sin_port = htons(9000);
ret = bind(mySock,(sockaddr*)&addrBind,sizeof(addrBind));
if (ret == SOCKET_ERROR)
{
cout<<"Bind Error"<<endl;
return 0;
}
//set non-blocking
int nMode = 1;
ioctlsocket(mySock,FIONBIO,(u_long FAR*) &nMode);
char recvchar[20];
sockaddr_in addrRev;
memset(&addrRev,0,sizeof(addrRev));
memset(recvchar,0,20);
int len = sizeof(sockaddr);
while (true)
{
if (recvfrom(mySock,recvchar,20,0,(sockaddr*)&addrRev,&len) == SOCKET_ERROR)
{
if (GetLastError() == WSAEWOULDBLOCK || GetLastError() == 10054)
{
continue;
}
else
{
cout<<"Receive Error!"<<GetLastError()<<endl;
return 0;
}
}
cout<<recvchar<<" from "<<inet_ntoa(addrRev.sin_addr)<<":"<<ntohs(addrRev.sin_port)<<endl;
sendto(mySock,recvchar,strlen(recvchar)+1,0,(sockaddr*)&addrRev,sizeof(sockaddr));
}
return 0;
}