关于getsockname函数的使用

时间:2021-09-16 01:51:32

转自出处


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