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