winston 发表于 2012-3-9 21:33:21

关于getsockname函数的使用

   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;
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;
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;
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;
}



winston 发表于 2012-10-19 10:13:03

刷新,冲掉垃圾广告标题。

ztenv 发表于 2013-9-26 17:25:55

广告真是个头疼的问题
页: [1]
查看完整版本: 关于getsockname函数的使用