https://www.tuicool.com/articles/V3Avey

getsockname和getpeername函数

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

定义如下:

[cpp] view plaincopy
  1. #include<sys/socket.h>
  2. int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
  3. int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);

对于这两个函数,如果函数调用成功,则返回0,如果调用出错,则返回-1。

使用这两个函数,我们可以通过套接字描述符来获取自己的IP地址和连接对端的IP地址,如在未调用bind函数的TCP客户端程序上,可以通过调用getsockname()函数获取由内核赋予该连接的本地IP地址和本地端口号,还可以在TCP的服务器端accept成功后,通过getpeername()函数来获取当前连接的客户端的IP地址和端口号。

如下面的客户端-服务器程序:

服务器端代码

[cpp] view plaincopy
  1. /*服务器端*/
  2. #define MAXLINE 4096
  3. #define PORT 6563
  4. #define LISTENQ 1024
  5. #include<stdio.h>
  6. #include<sys/socket.h>
  7. #include<netinet/in.h>
  8. #include<unistd.h>
  9. #include<string.h>
  10. #include<arpa/inet.h>
  11. int main() {
  12. int listenfd, connfd;
  13. struct sockaddr_in servaddr;//服务器绑定的地址
  14. struct sockaddr_in listendAddr, connectedAddr, peerAddr;//分别表示监听的地址,连接的本地地址,连接的对端地址
  15. int listendAddrLen, connectedAddrLen, peerLen;
  16. char ipAddr[INET_ADDRSTRLEN];//保存点分十进制的地址
  17. listenfd = socket(AF_INET, SOCK_STREAM, 0);
  18. memset(&servaddr, 0, sizeof(servaddr));
  19. servaddr.sin_family = AF_INET;
  20. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  21. servaddr.sin_port = htons(PORT);
  22. bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));//服务器端绑定地址
  23. listen(listenfd, LISTENQ);
  24. listendAddrLen = sizeof(listendAddr);
  25. getsockname(listenfd, (struct sockaddr *)&listendAddr, &listendAddrLen);//获取监听的地址和端口
  26. printf("listen address = %s:%d\n", inet_ntoa(listendAddr.sin_addr), ntohs(listendAddr.sin_port));
  27. while(1) {
  28. connfd = accept(listenfd, (struct sockaddr *)NULL, NULL);
  29. connectedAddrLen = sizeof(connectedAddr);
  30. getsockname(connfd, (struct sockaddr *)&connectedAddr, &connectedAddrLen);//获取connfd表示的连接上的本地地址
  31. printf("connected server address = %s:%d\n", inet_ntoa(connectedAddr.sin_addr), ntohs(connectedAddr.sin_port));
  32. getpeername(connfd, (struct sockaddr *)&peerAddr, &peerLen); //获取connfd表示的连接上的对端地址
  33. printf("connected peer address = %s:%d\n", inet_ntop(AF_INET, &peerAddr.sin_addr, ipAddr, sizeof(ipAddr)), ntohs(peerAddr.sin_port));
  34. }
  35. return 0;
  36. }

上面的代码中,在调用listen函数之后就获取监听套接字描述符对应的本地地址,在accept()函数后,由于accept返回了一个套接字描述符connfd用于表示该连接,所以可以对这个connfd调用getsockname函数和getpeername函数,分别获取内核赋予该连接的本地IP地址和连接的对端地址。

客户端代码

[cpp] view plaincopy
  1. /*客户端*/
  2. #define PORT 6563
  3. #include<stdio.h>
  4. #include<sys/socket.h>
  5. #include<netinet/in.h>
  6. #include<unistd.h>
  7. #include<string.h>
  8. #include<arpa/inet.h>
  9. int main(int argc, char **argv) {
  10. struct sockaddr_in servaddr;//服务器端地址
  11. struct sockaddr_in clientAddr;//客户端地址
  12. int sockfd;
  13. int clientAddrLen = sizeof(clientAddr);
  14. char ipAddress[INET_ADDRSTRLEN];//保存点分十进制的ip地址
  15. if(argc < 2) {
  16. printf("parameter error");
  17. }
  18. sockfd = socket(AF_INET, SOCK_STREAM, 0);
  19. memset(&servaddr, 0, sizeof(servaddr));
  20. servaddr.sin_family = AF_INET;
  21. servaddr.sin_port = htons(PORT);
  22. if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
  23. printf("server address error\n");//地址参数不合法
  24. }
  25. connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));//向服务器端发起连接请求
  26. getsockname(sockfd, (struct sockaddr*)&clientAddr, &clientAddrLen);//获取sockfd表示的连接上的本地地址
  27. printf("client:client ddress = %s:%d\n", inet_ntop(AF_INET, &clientAddr.sin_addr, ipAddress, sizeof(ipAddress)), ntohs(clientAddr.sin_port));
  28. return 0;
  29. }

在客户端的代码中,调用connect函数后,即可调用getsockname来获连接上的本地地址。

代码的运行结果如下:

服务区端输出

客户端输出

从上面的代码中可以看到,服务器端listenfd套接字描述符对应的地址即为绑定的通配IP地址和指定的端口,而connfd套接字描述符对应的连接的服务器端的地址为内核赋予的地址和用户指定的端口。

上面的客户端与服务器端的代码中使用了函数inet_ntoa,inet_pton对32位的地址进行转换,其中inet_ntoa是较老的函数,与它一起的还有函数inet_addr和inet_ntoa,这三个函数的定义如下:

[cpp] view plaincopy
  1. #include<arpa/inet.h>
  2. int inet_aton(const char *strptr, struct in_addr *addrptr);
  3. in_addr_t inet_addr(const char *strptr);
  4. char *inet_ntoa(struct in_addr inaddr);

inet_aton与inet_addr函数的功能类似,都是将点分十进制的字符串表示的IP地址转换成32位的网络字节序的IPv4地址。

inet_ntoa函数将32位的网络字节序的IPv4地址转换成点分十进制的字符串表示的IP地址,inet_addr函数已被废弃,并且这三个函数只针对IPv4地址有效,在点分十进制数串和32位的网络字节序二进制值间进行转换,如果要对于IPv4和IPv6都适用,那么使用下面两个函数:

[cpp] view plaincopy
  1. #include<arpa/inet.h>
  2. int inet_pton(int family, const char *strptr, void *addrptr);
  3. const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

函数中的p和n分别代表表达式(presentation)和数值(numeric)

所以inet_pton函数将strptr指针所指的字符串转换为网络地址(IPv4和IPv6),再将地址保存到addrptr指向的结构体中,inet_ntop将网络地址转为字符串表示的地址,结果存放在strptr中,len参数是strptr的大小。
这两个函数支持IPv4和IPv6,所以需要通过参数family来指定,当前要转换的是IPv4地址还是IPv6地址。

Reference

《UNIX网络编程 卷1:套接字联网API(第3版)》

getsockname函数与getpeername函数的使用相关推荐

  1. getpeername函数与getsockname函数的介绍

    getpeername函数用于获取与某个套接字关联的外地协议地址 getsockname函数用于获取与某个套接字关联的本地协议地址 函数定义如下: #include<sys/socket.h&g ...

  2. render函数和redirect函数的区别+反向解析

    render函数和redirect函数的区别+反向解析 1.视图函数:一定是要包含两个对象的(render源码里面有HttpResponse对象)   request对象:----->所有的请求 ...

  3. Python day10 global关键字、函数递归、匿名函数、map函数的用法详解

    1.global关键字 引用全局变量,在局部全局变量改变,也会改变,global相当于指针,将地址指向全局变量的name name='littlepage'def littepage():global ...

  4. C++ 笔记(13)— 函数(函数声明、函数定义、函数调用[传值、指针、引用]、函数参数默认值、函数重载)

    每个 C++ 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数. 1. 函数声明 函数声明告诉编译器函数的名称.返回类型和参数.函数声明包括以下几个部分: ret ...

  5. Go 学习笔记(16)— 函数(02)[函数签名、有名函数、匿名函数、调用匿名函数、匿名函数赋值给变量、匿名函数做回调函数]

    1. 函数签名 函数类型也叫做函数签名,可以使用 fmt.Printf("%T") 格式化参数打印函数类型. package mainimport "fmt"f ...

  6. Go 学习笔记(15)— 函数(01)[函数定义、函数特点、多值返回、实参形参、变长参数,函数作为参数调用]

    1. 函数定义 Go 语言最少有个 main() 函数.函数声明告诉了编译器函数的名称,返回类型和参数. func funcName(parameter_list)(result_list) {fun ...

  7. MySQL 学习笔记(3)— 字符串函数、数值函数、日期时间函数、流程函数、聚集函数以及分组数据

    1. 字符串函数 MySQL 的常用函数包括字符串函数.数值函数.日期时间函数.流程函数等. SELECT ascii("abc"),char(97),concat("h ...

  8. 经常可能会用到的【函数节流和函数防抖】记录下,做下区分

    今天突然被人问到,函数节流和函数防抖的区别是什么, 结果我脑子一热直接举了个滚动条的粟子说是优化高频率执行的手段,就记得自己是用setTimeout来实现的. 完了区别是什么??哪个是哪个都蒙B了 回 ...

  9. c语言随机数生成0 99函数,C语言生成随机数的函数、延时函数

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 下面C语言代码使用了生成随机数的函数.延时函数.请大家仔细观察其显示效果. 从以下代码,我们可以得出一个重要的结论:当上述两类函数被放入循环时,应作出一定 ...

最新文章

  1. Spring Cloud分布式微服务云架构—源码结构图
  2. node.js:fs.open 和 fs.write 读取文件和改写文件
  3. java实现递归下降分析_使用递归实现检查未知层级目录中的文件-Java实用技能
  4. vs.net2003无法打开*.xsd文件的解决方法
  5. Oracle具有开放性吗,Oracle数据库的特点与工作原理
  6. 关于抠图的一些文章方法收集
  7. PCL的学习必要性、重要性、意义及最初——持续修改中
  8. 绝望:对不完的数,加不完的班
  9. BFS迷宫问题模型(具体模拟过程见《啊哈算法》)
  10. Bootstrap 默认栅格系统
  11. 可视化数据图表制作注意事项
  12. sklearn库里几种回归模型
  13. SecureCRT 下载安装与连接(转)
  14. Keil 编译显示变量重复定义问题
  15. H3C交换机级联式堆叠配置方式
  16. hp打印机无法与计算机,电脑无法连接HP打印机怎么办?
  17. shell 打印九九乘法表
  18. 2014智联卓聘积分获取新攻略
  19. PyQt5制作简易桌面
  20. HTTP1.0,HTTP1.1,HTTP2.0,SPDY,HTTPS你应该知道的一些事

热门文章

  1. KnockoutJS-快速入门
  2. 运用Arc Hydro提取河网
  3. ubuntu 使用apt-get install 安装php5.6--php7
  4. MYSQL AND OR的联用
  5. hdu5823 (附带数的二进制子集)
  6. iOS GorupBy
  7. silverligh的数据访问
  8. AndEngine引擎之SmoothCamera 平滑摄像机
  9. 基于RBAC模型的通用企业权限管理系统
  10. 新风系统风速推荐表_新风系统风速标准及与噪音的关系