首页 > C语言网络编程:bind函数详解

C语言网络编程:bind函数详解

文章目录

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

函数功能

bind API能够将套接字文件描述符、端口号和ip绑定到一起

注意:

绑定的一定是自己的 ip和和端口,不是对方的;比如对于TCP服务器来说绑定的就是服务器自己的ip和端口

函数头文件
 #include           /* See NOTES */#include 
函数使用

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可以看到结构体原型

    使用该结构体时需要包含头文件,且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 
#include 
#include 
#include 
#include 
#include  //struct sockadd_in 结构体的头文件
#include 
#include 
#include void print_err(char *str, int line, int err_no) { printf("%d, %s :%s
",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
  • uint16_t htons(uint16_t hostshort); 函数全拼为host to net short
  • 函数功能

    a. 将端口从"主机端序" 转为 “网络端序”

    b. 如果给定的端口不是short,则转为short
  • 返回值: 函数的调用永远都是成功的,返回转换后的端口号
htons兄弟函数htonl,ntohs,ntohl
  • htonlhtons唯一的区别时,转换完的端口号为long
  • ntohshtons恰好相反,是从网络字节序转换为主机字节序
  • ntohl 表示从网络字节转换为主机序,同时转换完的端口号为long
为什么要进行端口的大小端序的转换

大端序:

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;

小端序:

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

大小端序是由具体的操作系统来决定的

可以使用如下代码测试系统是大端还是小端:

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

同样,网络通信的时候发送端计算机和接收端计算机可能端序不一致,比如发送者是大端序,接受者是小端序,如果通信时数据的端序处理不好很可能出现乱码,甚至无法接收到数据。

如果发送者和接受者端序一致则也能够正常传输数据,不用htons函数进行转换,不过保证数据序列正确的得进行传输,建议使用htons函数进行端口号的转换

inet_addr函数
  • in_addr_t inet_addr(const char *cp);
  • 函数功能:

    a. 将字符串形式的IP "192.168.102.169"转换为IPV4的32位无符号整型数的IP

    b. 将无符号整型数的ip,从主机端序转为网络端序
  • 参数:字符串形式的ip
  • 返回值:永远成功,返回网络端序的、32位无符号整型数的ip

更多相关:

  • 草色新雨中, 松声晚窗里。之前我们学习 Power Query 都是用鼠标就完成了很多复杂的操作。虽然 PowerQuery 已经将大部分常用功能内置成到功能区。基本能完成我们大部分的报表自动化功能。但是总有些复杂的或者个性化的问题是开发团队没有预先想到的,这时我们就需要学习 M 语言。一、M 语言在哪里?M语言的函数公式有三个地...

  • 前言从2020年3月份开始,计划写一系列文档--《小白从零开始学编程》,记录自己从0开始学习的一些东西。第一个系列:python,计划从安装、环境搭建、基本语法、到利用Django和Flask两个当前最热的web框架完成一个小的项目第二个系列:可能会选择Go语言,也可能会选择Vue.js。具体情况待定,拭目以待吧。。。基本概念表达式表...

  • 1.1函数1.1.1什么是函数函数就是程序实现模块化的基本单元,一般实现某一功能的集合。函数名:就相当于是程序代码集合的名称参数:就是函数运算时需要参与运算的值被称作为参数函数体:程序的某个功能,进行一系列的逻辑运算return 返回值:函数的返回值能表示函数的运行结果或运行状态。1.1.2函数的作用函数是组织好的,可重复使用的,用来...

  • 原标题:基于Python建立深度神经网络!你学会了嘛?图1 神经网络构造的例子(符号说明:上标[l]表示与第l层;上标(i)表示第i个例子;下标i表示矢量第i项)单层神经网络图2 单层神经网络示例神经元模型是先计算一个线性函数(z=Wx+b),接着再计算一个激活函数。一般来说,神经元模型的输出值是a=g(Wx+b),其中g是激活函数(...

  • 在学习MySQL的时候你会发现,它有非常多的函数,在学习的时候没有侧重。小编刚开始学习的时候也会有这个感觉。不过,经过一段时间的学习之后,小编发现尽管函数有很多,但是常用的却只有那几个。今天小编就把常用的函数汇总一下,为大家能够能好的学习MySQL中的函数。MySQL常使用的函数大概有四类。时间函数、数学函数、字符函数、控制函数。让我...

  • 下面的源码给出了使用boost::asio进行域名解析的方法. //g++ -g resolver_demo.cpp -o resolver_demo -lboost_system -lpthread //#include #include #include

  • pc 端配置 点击pc端无线链接图标编辑链接以太网编辑IPv4设置方法:与其他计算机共享根据putty获取的动态ip使用ssh登录 解决 ip 无法登录问题 设置 pc 端 ip 和开发板 ip 在同一个网段 比如开发板 ip 是 10.42.0.123 可以设置自己机器的 ip 为 10.42.0.11 sudo ifcon...

  • 原文:TCP/IP 简介     第一节:TCP/IP 简介 第二节:TCP/IP 寻址 第三节:TCP/IP 协议 第四节:TCP/IP 邮件     TCP/IP 是用于因特网 (Internet) 的通信协议。     计算机通信协议 计算机通信协议是对那些计算机必须遵守以便彼此通信的规则的描述。     什么是 TC...

  • #保存一万条命令记录 sed -i 's/^HISTSIZE=1000/HISTSIZE=10000/g' /etc/profile#在/etc/profile的文件尾部添加如下行数配置信息 ######jiagu history xianshi######### USER_IP=`who -u am i 2>/dev/null |...

  • TCP/IP基础概念及通信过程举例   出现 上个世纪60年代,由于中央集中式网络的容灾性较弱,以美国国防部为中心的一家组织研究出分组交换网络。后来为了验证分组交换技术的实用性,ARPANET出现了,并且在3年内逐渐发展,由4个节点发展至34个节点。20世纪70年代前半叶,ARPANET一个机构研制出了TCP/IP,1982年具体规范...

  •     socket这个词可以表示很多概念: 在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP地址+端口号”就称为socket。 在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。 socket本身有“插座”...