getpeername函数与getsockname函数的介绍

getpeername函数用于获取与某个套接字关联的外地协议地址

getsockname函数用于获取与某个套接字关联的本地协议地址

 

函数定义如下:

#include<sys/socket.h>
 
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
 
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
调用成功,则返回0,如果调用出错,则返回-1

 

 getpeername只有在连接建立以后才调用,否则不能正确获得对方地址和端口,所以它的参数描述字一般是已连接描述字而非监听套接口描述字。
    没有连接的UDP不能调用getpeername,但是可以调用getsockname和TCP一样,它的地址和端口不是在调用socket就指定了,而是在第一次调用sendto函数以后。
    已经连接的UDP,在调用connect以后,这2个函数(getsockname,getpeername)都是可以用的。但是这时意义不大,因为已经连接(connect)的UDP已经知道对方的地址。

  需要这两个函数的理由如下:

  •  在一个没有调用bind的TCP客户上,connect成功返回后,getsockname用于返回由内核赋予该连接的本地IP地址和本地端口号。

  •  在以端口号为0调用bind(告知内核去选择本地临时端口号)后,getsockname用于返回由内核赋予的本地端口号。

  •  在一个以通配IP地址调用bind的TCP服务器上,与某个客户的连接一旦建立(accept成功返回),getsockname就可以用于返回由内核赋予该连接的本地IP地址。在这样的调用中,套接字描述符参数必须是已连接套接字的描述符,而不是监听套接字的描述符。

  •  当一个服务器的是由调用过accept的某个进程通过调用exec执行程序时,它能够获取客户身份的唯一途径便是调用getpeername。

 

手册中介绍

GETPEERNAME(2)                                                                Linux Programmer's Manual                                                                GETPEERNAME(2)

NAME
       getpeername - get name of connected peer socket

SYNOPSIS
       #include <sys/socket.h>

       int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

DESCRIPTION
       getpeername()  returns  the  address of the peer connected to the socket sockfd, in the buffer pointed to by addr.  The addrlen argument should be initialized to indicate the
       amount of space pointed to by addr.  On return it contains the actual size of the name returned (in bytes).  The name is truncated if the buffer provided is too small.

       The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

ERRORS
       EBADF  The argument sockfd is not a valid descriptor.

       EFAULT The addr argument points to memory not in a valid part of the process address space.

       EINVAL addrlen is invalid (e.g., is negative).

       ENOBUFS
              Insufficient resources were available in the system to perform the operation.

       ENOTCONN
              The socket is not connected.

       ENOTSOCK
              The file descriptor sockfd does not refer to a socket.

CONFORMING TO
       POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD (getpeername() first appeared in 4.2BSD).

NOTES
       The third argument of getpeername() is in reality an int * (and this is what 4.x BSD and libc4 and libc5 have).  Some POSIX confusion resulted in the present socklen_t,  also
       used by glibc.  See also accept(2).

       For  stream sockets, once a connect(2) has been performed, either socket can call getpeername() to obtain the address of the peer socket.  On the other hand, datagram sockets
       are connectionless.  Calling connect(2) on a datagram socket merely sets the peer address for outgoing datagrams sent with write(2) or recv(2).  The caller of connect(2)  can
       use  getpeername()  to  obtain the peer address that it earlier set for the socket.  However, the peer socket is unaware of this information, and calling getpeername() on the
       peer socket will return no useful information (unless a connect(2) call was also executed on the peer).  Note also that the receiver of a datagram can obtain the  address  of
       the sender when using recvfrom(2).

SEE ALSO
       accept(2), bind(2), getsockname(2), ip(7), socket(7), unix(7)

COLOPHON
       This page is part of release 4.04 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest version of this page, can be
       found at http://www.kernel.org/doc/man-pages/.

Linux                                                                                 2015-12-28                                                                       GETPEERNAME(2)
GETSOCKNAME(2)                                                                Linux Programmer's Manual                                                                GETSOCKNAME(2)

NAME
       getsockname - get socket name

SYNOPSIS
       #include <sys/socket.h>

       int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

DESCRIPTION
       getsockname()  returns  the current address to which the socket sockfd is bound, in the buffer pointed to by addr.  The addrlen argument should be initialized to indicate the
       amount of space (in bytes) pointed to by addr.  On return it contains the actual size of the socket address.

       The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

ERRORS
       EBADF  The argument sockfd is not a valid descriptor.

       EFAULT The addr argument points to memory not in a valid part of the process address space.

       EINVAL addrlen is invalid (e.g., is negative).

       ENOBUFS
              Insufficient resources were available in the system to perform the operation.

       ENOTSOCK
              The file descriptor sockfd does not refer to a socket.

CONFORMING TO
       POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD (getsockname() first appeared in 4.2BSD).

NOTES
       The third argument of getsockname() is in reality an int * (and this is what 4.x BSD and libc4 and libc5 have).  Some POSIX confusion resulted in the present socklen_t,  also
       used by glibc.  See also accept(2).

SEE ALSO
       bind(2), socket(2), getifaddrs(3), ip(7), socket(7), unix(7)

COLOPHON
       This page is part of release 4.04 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest version of this page, can be
       found at http://www.kernel.org/doc/man-pages/.

Linux                                                                                 2015-12-28                                                                       GETSOCKNAME(2)

我们可以通过套接字描述符来获取自己的IP地址和连接对端的IP地址

服务器代码:

/*服务器端*/
#define MAXLINE 4096
#define PORT 6563
#define LISTENQ 1024
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
 
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<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
 
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;
}

 

 

 

 

 

 

 

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值