C语言网络编程:bind函数详解
文章目录
- 函数功能
- 函数头文件
- 函数使用
- 函数参数
- 函数举例
- 为什么需要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
htonl
与htons
唯一的区别时,转换完的端口号为longntohs
与htons
恰好相反,是从网络字节序转换为主机字节序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函数详解相关推荐
- linux网络编程常用函数详解与实例(socket--bind--listen--accept)
常用的网络命令: netstat 命令netstat是用来显示网络的连接,路由表和接口统计等网络的信息.netstat有许多的选项我们常用的选项是 -an 用来显示详细的网络状态.至于其它的选项我们可 ...
- bind() c语言,c/c++ 标准库 bind 函数详解
bind函数定义在头文件 functional 中.可以将 bind 函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来"适应"原对象的参数列表. bin ...
- gets和fgets函数及其区别,C语言gets和fgets函数详解
gets和fgets函数及其区别,C语言gets和fgets函数详解 每当讨论 gets 函数时,大家不由自主地就会想起 1988 年的"互联网蠕虫",它在 UNIX 操作系统的 ...
- puts和fputs函数及其区别,C语言puts和fputs函数详解
puts和fputs函数及其区别,C语言puts和fputs函数详解 与 gets 函数一样,对于 puts 函数,同样建议使用 fputs 函数来代替 puts 函数.如下面的示例代码所示: int ...
- Visual C++网络编程经典案例详解 第9章 实用播放器 数据读取与播放控制 识别数据文件信息
识别数据文件信息主要是指对mp3数据格式识别 定义顺序代码如下 typedef struct mp3_struct //自定义mp3结构体 {char heade[3]; //tag字符标记char ...
- C语言strcpy、strcnpy函数详解
C语言strcpy.strcnpy函数详解 一.strcpy函数 1.函数原型 2.参数.返回值解析 3.注意事项 4.strcpy函数模拟实现 二.strncpy函数 1.函数原型 2.与strcp ...
- java的匿名函数_JAVA语言中的匿名函数详解
本文主要向大家介绍了JAVA语言中的匿名函数详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. 一.使用匿名内部类 匿名内部类由于没有名字,所以它的创建方式有点儿奇怪.创建格式如下: ...
- c语言中bind函数,c/c++ 标准库 bind 函数详解
bind函数定义在头文件 functional 中.可以将 bind 函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来"适应"原对象的参数列表. bin ...
- C语言strcat、strncat函数详解
C语言strcat.strncat函数详解 一.strcat函数 1.函数原型 2.函数参数.返回值解析 3.函数作用 4.注意事项 5.strcat函数模拟实现 二.strncat函数 1.函数原型 ...
最新文章
- 成为优秀程序员的十个Tips
- 特征工程(part2)--数值型数据
- 信安教程第二版-第19章操作系统安全保护
- python openstack vpc互通_深入浅出新一代云网络——VPC中的那些功能与基于OpenStack Neutron的实现(一)-简述与端口转发...
- Java-Set、Map
- 电视商城之maven热部署
- 深度揭秘阿里云 Serverless Kubernetes
- js中获取时间new date()的用法和获取时间戳
- arXiv上引用文章在bibtex下的引用格式
- html做出文字凹凸效果,css3怎么实现字体凹陷凸出效果?(附代码)
- 解决:Mac下的Mounty卷不能在读/写模式下重新挂载.可能是因为先前没有完全卸载(安全删除)
- HDU-6357Hills And Valleys(用最长可重复公共子序列求最长非递减子序列)
- 没有什么软文是营销圈拯救不了的?
- 三个灭点来衡量一个立方体
- 【AI with ML】第 8 章 :使用 TensorFlow 创建文本
- php程序员需要什么资质,微信小程序服务类目及资质要求
- 对展开运算符和object.assign()的理解
- 7 个支持敏捷的开源项目管理工具,更好地管理项目
- 视频批量截取方法,怎样同时对多个视频的一部分进行截取?
- Java基础之——动态代理
热门文章
- day13 paramiko、数据库表操作
- [英文面試]如何寫面試後的感謝信
- PowerShell 2.0 实践(十二)管理 SQL Server 2008 R2(1)
- ASP.NET禁用视图状态
- datagrid DataFormatString
- mysql 主从 MySQLroute_mysql主从复制
- html显示数据库图片django,django将图片上传数据库后在前端显式的方法
- π是无理数证明定积分_证明圆周率是无理数很容易?人类花了2000年!
- php判据的例子,科学网—Hartle-Srednicki判据 - 李淼的博文
- nginx 没有cookie_Nginx灰度升级实现说明