获取本机ip和获取远程ip

getsockname与getpeername是返回套接口关联的本地协议地址和远程协议地址。

int getsockname(int sockfd, struct sockaddr * localaddr, socken_t * addrlen);

int getpeername(int sockfd, struct sockaddr * peeraddr, socken_t * addrlen);

返回0表示成功,返回1表示出错

参数sockfd表示你要获取的套接口的描述字。

localaddr返回本地协议地址描述结构, peeraddr返回远程协议地址描述结构,addrlen分别是上述2个结构的长度。


补充:getsockname和getpeername调度时机很重要,如果调用时机不对,则无法正确获得地址和端口。

TCP

对于服务器来说,在bind以后就可以调用getsockname来获取本地地址和端口,虽然这没有什么太多的意义。getpeername只有在链接建立以后才调用,否则不能正确获得对方地址和端口,所以他的参数描述字一般是链接描述字而非监听套接口描述字。

对于客户端来说,在调用socket时候内核还不会分配IP和端口,此时调用getsockname不会获得正确的端口和地址(当然链接没建立更不可能调用getpeername),当然如果调用了bind 以后可以使用getsockname。想要正确的到对方地址(一般客户端不需要这个功能),则必须在链接建立以后,同样链接建立以后,此时客户端地址和端口就已经被指定,此时是调用getsockname的时机。

UDP

UDP分为链接和没有链接2种(这个到UDP与connect可以找到相关内容)

没有链接的UDP不能调用getpeername,但是可以调用getsockname,和TCP一样,他的地址和端口不是在调用socket就指定了,而是在第一次调用sendto函数以后

已经链接的UDP,在调用connect以后,这2个函数都是可以用的(同样,getpeername也没太大意义。如果你不知道对方的地址和端口,不可能会调用connect)。

例如:

/*服务器端*/
#define MAXLINE 4096
#define PORT 6563
#define LISTENQ 1024
#include
#include
#include
#include
#include
#include

int main() {
  int listenfd, connfd;
  struct sockaddr_in servaddr;//服务器绑定的地址
  struct sockaddr_in listendAddr, connectedAddr, peerAddr;//分别表示监听的地址,连接的本地地址,连接的对端地址
  int listendAddrLen, connectedAddrLen, peerLen;
  char ipAddr[INET_ADDRSTRLEN];//保存点分十进制的地址
  listenfd = socket(AF_INET, SOCK_STREAM, 0);
  memset(&servaddr, 0, sizeof(servaddr));

  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(PORT);
  
  bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));//服务器端绑定地址

  listen(listenfd, LISTENQ);
  listendAddrLen = sizeof(listendAddr);
  getsockname(listenfd, (struct sockaddr *)&listendAddr, &listendAddrLen);//获取监听的地址和端口
  printf("listen address = %s:%d\n", inet_ntoa(listendAddr.sin_addr), ntohs(listendAddr.sin_port));

  while(1) {
    connfd = accept(listenfd, (struct sockaddr *)NULL, NULL);
    connectedAddrLen = sizeof(connectedAddr);
    getsockname(connfd, (struct sockaddr *)&connectedAddr, &connectedAddrLen);//获取connfd表示的连接上的本地地址
    printf("connected server address = %s:%d\n", inet_ntoa(connectedAddr.sin_addr), ntohs(connectedAddr.sin_port));
    getpeername(connfd, (struct sockaddr *)&peerAddr, &peerLen); //获取connfd表示的连接上的对端地址
    printf("connected peer address = %s:%d\n", inet_ntop(AF_INET, &peerAddr.sin_addr, ipAddr, sizeof(ipAddr)), ntohs(peerAddr.sin_port));
  }
  return 0;
}

/*客户端*/
#define PORT 6563
#include
#include
#include
#include
#include
#include

int main(int argc, char **argv) {
  struct sockaddr_in servaddr;//服务器端地址
  struct sockaddr_in clientAddr;//客户端地址
  int sockfd; 
  int clientAddrLen = sizeof(clientAddr);
  char ipAddress[INET_ADDRSTRLEN];//保存点分十进制的ip地址
  
  if(argc < 2) {
    printf("parameter error");
  }

  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(PORT);  
  if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
    printf("server address error\n");//地址参数不合法
  }

  connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));//向服务器端发起连接请求
  
  getsockname(sockfd, (struct sockaddr*)&clientAddr, &clientAddrLen);//获取sockfd表示的连接上的本地地址
 
  printf("client:client ddress = %s:%d\n", inet_ntop(AF_INET, &clientAddr.sin_addr, ipAddress, sizeof(ipAddress)), ntohs(clientAddr.sin_port));
  return 0;
}


你可能感兴趣的:(TCP)