文章目录

  • 函数功能
  • 函数头文件
  • 函数使用
  • 函数参数
  • 函数举例
  • 为什么需要bind函数
  • 服务器如何知道客户端的ip和端口号
  • htons函数
  • `htons`兄弟函数`htonl`,`ntohs`,`ntohl`
  • 为什么要进行端口的大小端序的转换
  • `inet_addr`函数
函数功能

bind API能够将套接字文件描述符、端口号和ip绑定到一起
注意:
绑定的一定是自己的 ip和和端口,不是对方的;比如对于TCP服务器来说绑定的就是服务器自己的ip和端口

函数头文件
 #include <sys/types.h>          /* See NOTES */#include <sys/socket.h>
函数使用

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

函数参数
  • sockfd 表示socket函数创建的通信文件描述符
  • addrlen 表示所指定的结构体变量的大小
  • addr 表示struct sockaddr的地址,用于设定要绑定的ip和端口
    struct sockaddr {sa_family_t sa_family;char        sa_data[14];
    }
    

    sa_family 用于指定AF_***表示使用什么协议族的ip
    sa_data 存放ip和端口
    这里有一个问题,直接向sa_data中写入ip和端口号有点麻烦,内核提供struct sockaddr_in结构体进行写入,通过/usr/include/linux/in.h可以看到结构体原型
    使用该结构体时需要包含<netinet/in.h>头文件,且sockaddr_in结构体是专门为tcp/ip协议族使用,其他协议族需要使用其对应的转换结构体,比如“域通信协议族” 使用的是sockaddr_un结构体

    struct sockaddr_in {__kernel_sa_family_t  sin_family;     /* Address family               */__be16                sin_port;       /* Port number                  */struct in_addr        sin_addr;       /* Internet address             *//* Pad to size of `struct sockaddr'. 设置IP端口号这个成员暂时用不到 */unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -sizeof(unsigned short int) - sizeof(struct in_addr)];
    };/* Internet address.填补相比于struct sockaddr所缺的字节数,保障强制转换不要出错 */
    struct in_addr {__be32  s_addr; // __be32是32位的unsigned int ,因为ipv4是无符号32位整型
    };
    

    可以看到以上sockaddr_in结构体中存放的端口和ip是分开的,所以设置起来非常方便,使用struct sockaddr_in设置后,让后将其强制转换为struct sockaddr类型,然后传递给bind函数即可

函数举例
struct sockaddr_in addr;
addr.sin_family = AF_INET; //设置tcp协议族
addr.sin_port = htons(6789); //设置端口号
addr.sin_addr.s_addr = inet_addr("192.168.1.105"); //设置ip地址ret = bind(skfd, (struct sockaddr*)&addr, sizeof(addr));

如果是跨局域网或者城域网通信,这里设置的ip地址一定为通信设备所在路由器的外网ip地址。

如下c代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h> //struct sockadd_in 结构体的头文件
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>void print_err(char *str, int line, int err_no) {printf("%d, %s :%s\n",line,str,strerror(err_no));_exit(-1);
}int main()
{int skfd = -1;skfd = socket(AF_INET, SOCK_STREAM, 0);if ( -1 == skfd) {print_err("socket failed",__LINE__,errno);}struct sockaddr_in addr;addr.sin_family = AF_INET; //设置tcp协议族addr.sin_port = htons(6789); //设置端口号addr.sin_addr.s_addr = inet_addr("192.168.102.169"); //设置ip地址int ret = bind(skfd, (struct sockaddr*)&addr, sizeof(addr));if ( -1 == ret) {print_err("bind failed",__LINE__,errno);}return 0;
}
为什么需要bind函数

bind函数就是让套接字文件在通信时使用固定的IP和端口号(针对服务器来说)
可以看到如上实现代码,调用socket函数创建的套接字仅仅执行了通信等协议,但是并没有指定通信时所需的ip地址和端口号

  • ip 是对方设备的唯一标识
  • 端口号 区分同一台计算机上的不同的网络通信进程

如果不调用bind函数指定ip和端口,则会自己指定一个ip和端口,此时违背了TCP通信的可靠性和面向连接的特点。

服务器如何知道客户端的ip和端口号

可以通过上文TCP通信模型中看到,客户端通信时不需要指定ip和端口号,直接创建一个socket套接字文件描述符即可参与通信。
此时当客户端和服务器建立连接的时候,服务器会从客户的数据包中提取出客户端ip和端口,并保存起来,如果是跨网通信,那么记录的就是客户端所在路由器的公网ip

htons函数
  • #include <arpa/inet.h>
  • uint16_t htons(uint16_t hostshort); 函数全拼为host to net short
  • 函数功能
    a. 将端口从"主机端序" 转为 “网络端序”
    b. 如果给定的端口不是short,则转为short
  • 返回值: 函数的调用永远都是成功的,返回转换后的端口号
htons兄弟函数htonl,ntohs,ntohl
  • htonlhtons唯一的区别时,转换完的端口号为long
  • ntohshtons恰好相反,是从网络字节序转换为主机字节序
  • ntohl 表示从网络字节转换为主机序,同时转换完的端口号为long
为什么要进行端口的大小端序的转换

大端序:
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
小端序:
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

大小端序是由具体的操作系统来决定的
可以使用如下代码测试系统是大端还是小端:

#include <stdio.h>
int main()
{int a = 1;char pc = *(char*)(&a);if (pc == 1)printf("第一个字节为1,小端存储\n");elseprintf("第一个字节为0,大端存储\n");return 0;
}

同样,网络通信的时候发送端计算机和接收端计算机可能端序不一致,比如发送者是大端序,接受者是小端序,如果通信时数据的端序处理不好很可能出现乱码,甚至无法接收到数据。
如果发送者和接受者端序一致则也能够正常传输数据,不用htons函数进行转换,不过保证数据序列正确的得进行传输,建议使用htons函数进行端口号的转换

inet_addr函数
  • <sys/socket.h> <netinet/in.h> <arpa/inet.h>
  • in_addr_t inet_addr(const char *cp);
  • 函数功能:
    a. 将字符串形式的IP "192.168.102.169"转换为IPV4的32位无符号整型数的IP
    b. 将无符号整型数的ip,从主机端序转为网络端序
  • 参数:字符串形式的ip
  • 返回值:永远成功,返回网络端序的、32位无符号整型数的ip

C语言网络编程:bind函数详解相关推荐

  1. linux网络编程常用函数详解与实例(socket--bind--listen--accept)

    常用的网络命令: netstat 命令netstat是用来显示网络的连接,路由表和接口统计等网络的信息.netstat有许多的选项我们常用的选项是 -an 用来显示详细的网络状态.至于其它的选项我们可 ...

  2. bind() c语言,c/c++ 标准库 bind 函数详解

    bind函数定义在头文件 functional 中.可以将 bind 函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来"适应"原对象的参数列表. bin ...

  3. gets和fgets函数及其区别,C语言gets和fgets函数详解

    gets和fgets函数及其区别,C语言gets和fgets函数详解 每当讨论 gets 函数时,大家不由自主地就会想起 1988 年的"互联网蠕虫",它在 UNIX 操作系统的 ...

  4. puts和fputs函数及其区别,C语言puts和fputs函数详解

    puts和fputs函数及其区别,C语言puts和fputs函数详解 与 gets 函数一样,对于 puts 函数,同样建议使用 fputs 函数来代替 puts 函数.如下面的示例代码所示: int ...

  5. Visual C++网络编程经典案例详解 第9章 实用播放器 数据读取与播放控制 识别数据文件信息

    识别数据文件信息主要是指对mp3数据格式识别 定义顺序代码如下 typedef struct mp3_struct //自定义mp3结构体 {char heade[3]; //tag字符标记char ...

  6. C语言strcpy、strcnpy函数详解

    C语言strcpy.strcnpy函数详解 一.strcpy函数 1.函数原型 2.参数.返回值解析 3.注意事项 4.strcpy函数模拟实现 二.strncpy函数 1.函数原型 2.与strcp ...

  7. java的匿名函数_JAVA语言中的匿名函数详解

    本文主要向大家介绍了JAVA语言中的匿名函数详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 一.使用匿名内部类 匿名内部类由于没有名字,所以它的创建方式有点儿奇怪.创建格式如下: ...

  8. c语言中bind函数,c/c++ 标准库 bind 函数详解

    bind函数定义在头文件 functional 中.可以将 bind 函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来"适应"原对象的参数列表. bin ...

  9. C语言strcat、strncat函数详解

    C语言strcat.strncat函数详解 一.strcat函数 1.函数原型 2.函数参数.返回值解析 3.函数作用 4.注意事项 5.strcat函数模拟实现 二.strncat函数 1.函数原型 ...

最新文章

  1. 成为优秀程序员的十个Tips
  2. 特征工程(part2)--数值型数据
  3. 信安教程第二版-第19章操作系统安全保护
  4. python openstack vpc互通_深入浅出新一代云网络——VPC中的那些功能与基于OpenStack Neutron的实现(一)-简述与端口转发...
  5. Java-Set、Map
  6. 电视商城之maven热部署
  7. 深度揭秘阿里云 Serverless Kubernetes
  8. js中获取时间new date()的用法和获取时间戳
  9. arXiv上引用文章在bibtex下的引用格式
  10. html做出文字凹凸效果,css3怎么实现字体凹陷凸出效果?(附代码)
  11. 解决:Mac下的Mounty卷不能在读/写模式下重新挂载.可能是因为先前没有完全卸载(安全删除)
  12. HDU-6357Hills And Valleys(用最长可重复公共子序列求最长非递减子序列)
  13. 没有什么软文是营销圈拯救不了的?
  14. 三个灭点来衡量一个立方体
  15. 【AI with ML】第 8 章 :使用 TensorFlow 创建文本
  16. php程序员需要什么资质,微信小程序服务类目及资质要求
  17. 对展开运算符和object.assign()的理解
  18. 7 个支持敏捷的开源项目管理工具,更好地管理项目
  19. 视频批量截取方法,怎样同时对多个视频的一部分进行截取?
  20. Java基础之——动态代理

热门文章

  1. day13 paramiko、数据库表操作
  2. [英文面試]如何寫面試後的感謝信
  3. PowerShell 2.0 实践(十二)管理 SQL Server 2008 R2(1)
  4. ASP.NET禁用视图状态
  5. datagrid DataFormatString
  6. mysql 主从 MySQLroute_mysql主从复制
  7. html显示数据库图片django,django将图片上传数据库后在前端显式的方法
  8. π是无理数证明定积分_证明圆周率是无理数很容易?人类花了2000年!
  9. php判据的例子,科学网—Hartle-Srednicki判据 - 李淼的博文
  10. nginx 没有cookie_Nginx灰度升级实现说明