1. 程式人生 > >關於getsockname函式的使用

關於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[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;
}