网络编程:套接字socket函数与绑定信息bind函数

套接字

  • 套接字是网络编程中的一种通信机制,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

进程间通信的方式:
1、管道(包括无名管道和命名管道);
2、消息队列;
3、信号量;
4、共享存储。
5、……( Socket和Streams支持不同主机上的两个进程IPC)。

绑定信息(绑定IP和端口)

  • 所谓绑定(bind)是指别人连接我只能通过我所绑定的端口,相当于,我买了一个手机,别人要想联系我,必须要知道我的手机号码,这时候,我需要怎么办呢?我需要给手机插上电话卡,固定一个电话号码,这样别人就能通过这个电话号码联系我。手机插上电话卡,固定一个电话号码,类似于绑定(bind)的过程,绑定(bind)为了固定一个端口号,别的网络程序就可以通过IP找到这个端口号,找到这个端口号就能找到这个端口号所对应的网络应用程序。

socket函数

int socket(int domain,int type,int protocol) ;
  • domain :地址域 指定网络层到底使用什么协议
    AF_INET : ipv4版本的ip协议
    AF_INET6 : ipv6版本的ip协议

  • type :套接字类型
    SOCK_DGRAM :用户数据报套接字
    SOCK_STREAM :流式套接字

  • protocol:协议
    SOCK_DGRAM :
    1.指定为0,表示采用默认协议,SOCK_DGRAM默认协议就是UDP协议
    2.IPPROTO_UDP ( 17)scoK_STREAM:
    1.指定为0,表示采用默认协议,
    SOCK_STREAM:
    1.指定为0,表示采用默认协议,默认协议是TCP协议
    2.IPPROTO_TCP (6)

  • 返回值: 返回一个套接字操作句柄,本质上是一个文件描述符,返回值大于等于o 则为创建成功,返回值小于0,则为创建失败

bind函数

int bind(int sockfd,const struct sockaddr *addr , socklen_t addr1en);
  • sockfd :套接字描述符(socket函数的返回值)
  • addr :告诉操作系统内核,当前进程要绑定的地址信息是啥
  • addrlen :绑定的地址信息长度是多少

struct sockaddr结构体的组成:

struct sockaddr{
    
    
sa_family_t sa_family;//地址域,(AF_INET,AF_INT6)2字节char
sa_data[14];//14字节
}
  • sockaddr在头文件#include <sys/socket.h>中定义,sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起了
  • 注意:
    1.struct sockaddr这个结构体是一个通用的地址信息结构,并不是某一个具体的地址信息结构

struct sockaddr_in结构体的组成:

在这里插入图片描述

  • sockaddr_in在头文件#include<netinet/in.h>或#include<arpa/inet.h>中定义,该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中

总结:

在网络编程中我们会对sockaddr_in结构体进行操作,使用sockaddr_in来建立所需的信息,最后使用类型转化就可以了。一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数:sockaddr_in用于socket定义和赋值;sockaddr用于函数参数。

编写socket函数与bind函数

#inclue<stdio.h>
#include<unistd.h>
//网络编程
#include<sys/socket.h>
#include<netinet/in.h>//互联网地址簇
#include<arpa/inet.h> //信息转化

int main() {
    
    
	//1.创建套接字
	int sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	if(sockfd<0) {
    
    
		perror("socket false");
		return -1;
	}
	//2.绑定地址
	struct sockaddr_in addr;
	addr.sin_family=AF_INET;
	//将ip地址转化为无符号32位
	//将unit32转化为主机字节序转化为网络字节序
	//htonl只能完成第二件事情
	//将字符串转化为网络字节序
	addr.sin_addr.s_addr=inet_addr("192.168.21.128");
	//端口转换为网络字节序
	addr.sin_port=htons(19999);
	//绑定地址信息
	int ret=bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
	if(ret<0) {
    
    
		perror("bind false");
		return -1;
	}
	while(1) {
    
    
		sleep(1);
	}
	return 0;
}

运行结果:sockfd的文件描述符为3,且为一个软连接,闪烁表示源文件不存在,我们之前在管道中也遇见过,因为是直接进入内核内部的缓冲区进操作的,缓冲区并没有文件:
在这里插入图片描述
netstat -anp| grep 【端口号】查看绑定端口的相应信息:
在这里插入图片描述

  • udp:当前19999端口是udp所占用
  • 192.168.21.128:19999:当前服务端监听的ip和端口
  • 0.0.0.0:* :表示能接收任意ip和任意地址
  • 3760:进程号
  • ./test_socket:进程信息
  • 当前19999端口已经被3760进程所占用

注意
1.一个进程可以绑定多个端口,但一个端口只能绑定一个进程
2.如果客户端想绑定端口号,一定要调用发送信息函数之前绑定( bind )端口,因为在发送信息函数( sendto, 或 write ),系统会自动给当前网络程序分配一个随机端口号,这相当于随机绑定了一个端口号,这里只会分配一次,以后通信就以这个随机端口通信,我们再绑定端口号的话,就会绑定失败。如果我们放在发送信息函数( sendto, 或 write )之前绑定,那样程序将以我们绑定的端口号发送信息,不会再随机分配一个端口号。

猜你喜欢

转载自blog.csdn.net/cckluv/article/details/111084311