套接字编程

网络编程:网络基础1,套接字编程,网络基础2,网络基础3,高级io(多路复用,多路转接(高并发网络编程))
socket(伯克利套接字)
计算机网络发展
信息发送:
数据----->交换机---->另一台交换机----->交换机连接的其中一台电脑
但是每一台交换机连接的计算机和交换机都是很多的,那交换机如何区分这些数据要发送到拿一台电脑呢,这个时候就出现了路由器,替代了交换机,路由器可以选择网络(路径选择),这要就可以实现更大的网络,这就是路由器组成了局域网。
局域网,城域网,广域网:网络覆盖范围不同
因特网(国际化广域网),互联网
我们平时所上的网络就是大一点的局域网
IP地址:外网络中唯一的标识一台主机
端口:在一台主机上唯一标识一台进程
网络上传输的是光电信号(高低电平)
协议:通信双方的数据格式约定
网络互联的基础,相同的网络通信协议的制定
协议分层:作用解耦合,按照服务,接口,协议对通信进行分层,分层之后网络通信环境更加清晰,更加方便,形成标准之后,才能形成互联
osi七层参考模型:(也叫开放互联模型)------按照服务,接口,协议,对整个复杂的网络通信环境进行层次划分,形成标准实现网络互联
从上到下是:应用层-表示层-会话层-传输层-网络层-链路层-物理层
tcp/ip五层参考模型:
应用层:负责应用程序之间的数据沟通;HTTP,FIP
传输层:端(端点/端口)与端之间的数据传输;TCP/UDP
网络层:地址管理与路由选择;IP协议,典型设备路由器
链路层:相邻设备之间的数据选择;以太网协议,典型设备交换机
物理层:负责光电信号的传输;以太网协议,典型设备集线器
应用层由程序员实现,其他都由操作系统实现。
网络通信数据传输流程:

从上到下的过程就叫数据的封装,在对端电脑上解析的过程就叫分用

完成最后一步也就是完成数据链路层,然后物理层通过网卡进行发送,发送到对端电脑,再反向解析,最后解析出数据

我们所说的协议就是一个结构体头部

 

 

 

套接字编程:


 

udp编程:
api接口介绍:
 1.创建套接字-----通过套接字使进程与网卡之间建立联系,内核中创建socket结构体
 int socket(int domain, int type, int protocol);
⦁    domain:  地址域         一般使用AF_INET 意思就是使用ipv4网络协议的地址域
⦁    type:    套接字类型    SOCK_STREAM 流式套接字提供字节流服务,默认协议tcp协议                   SOCK_DGRAM  提供数据报传输服务,默认使用udp协议
TCP本来就是提供流式套接字协议,udp提供数据报传输
⦁    protocol:传输层协议。协议在man socketz种已经看不见了
a.    0   根据套接字类型使用默认协议            
b.    IPPROTO_TCP  TCP协议            
c.    IPPROTO_UDP UDP协议
        
返回值:成功返回套接字描述符 失败:-1  
2.为套接字绑定地址信息:
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
⦁    socket:创建的套接字返回的套接字描述符
⦁    my_addr:地址信息
⦁    addrlen:地址信息长度
返回值:成功返回0 失败返回-1

3.接收数据
       ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);

⦁    sockfd:套接字描述符
⦁    buf:用于 接收的数据的缓冲区
⦁    len:想要接受的数据长度
⦁    flags:选项标志0表示阻塞接收数据
⦁    src_addr:发送端地址信息,传入参数
⦁    addrlen:地址信息长度(输入输出型参数,指定想要的长度,返回实际长度),你指定要1000个字节,那人家发送的数据只有100个字节你也要全部接收,这个时候返回值就是实际接受的字节数
一个端口两个字节,一个IP地址4个字节
⦁    返回值;返回直接接收的长度  失败返回-1

4.发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);
⦁    sockfd:套接字描述符
⦁    buf:要发送的数据
⦁    len:要发送的数据长度,发送数据并不会按照实际数据长度来发送,也不是\0而是我们实际指定的数据大小,就算100个字节的实际数据,只要你发送字节长度写的是1000,那它就会从缓冲区读取1000个字节的长度,那非实际数据部分他就会用0;来补充
⦁    flags:0默认阻塞发送数据
⦁    dest_addr:目的端地址
⦁    addrlen:地址长度
返回值:实际的数据发送长度,失败返回-1

5.关闭套接字
int close(int fd)
fd:套接字描述符
返回值:成功返回0失败返回-1

udp编程创建套接字5个接口: 1.创建套接字,2.为套接字绑定地址信息,3.接收数据,4.发送数据,5.关闭套接字

绑定之后网卡就可以自动的接收数据,将接收到的数据放到对应的缓冲区当中,然后接收数据的时候(recvfrom就是直接去对应的缓冲区中拿数据)
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);

由于ipv4和ipv6的协议不同,所承载信息的结构体也不同,由于两者地址域信息不同,那么我们只需要通过参数传进来确定地址域的信息,再自动进行根据地址域判断是是哪一种地址域再通过地址域解析剩下的结构体数据就可以了,这样是为了寻求接口的统一性

potr:端口
每个socket绑定的端口号都不一样
网卡接收到网络中发来的数据之后,通过端口号去内核缓冲区找对应的socket,找到之后就把数据放到对应端口的缓冲区中

socket这个词可以表示很多概念: 在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP地址+端口号”就称为socket。socket本身还有插座的意思,一个程序插入到套接字里面就好比通上了电,这样就可以通信了,应用就可以通过套接字从网络中获取发送给自己的信息。类比, socket 其实就和灯泡的插座一样。
灯泡插进带电的插座, 就会亮。
就如, 应用程序插到一个套接字里面的话, 就可以进行通信了。
套接字的背后就是传输数据的通道。
通道和我们的通信对象是相连的。

socket是应用层和传输层之间的桥梁

因为端口和地址信息都是要在网络上传输的,因此需要字节序转换
       uint32_t htonl(uint32_t hostlong);
    将32位的数据从主机字节序转换为网络字节序
       uint16_t htons(uint16_t hostshort);
    将16位的数据从主机字节序转换为网络字节序
       uint32_t ntohl(uint32_t netlong);
    将32位的数据从网络字节序转换为主机字节序
       uint16_t ntohs(uint16_t netshort);
    将16位的数据从网络字节序转换为主机字节序

端口我们只能进行htons进行绑定,因为端口为两个字节,要是使用32位htonl转换之后存在补位就会使得端口错误


in_addr_t inet_addr(const char *cp);
将字符串点分十进制ip地址转换为网络字节序ip地址
char *inet_ntoa(struct in_addr in);
将网络字节序ip地址转换为点分十进制ip地址

ipv4地址结构

服务端程序:

客户端程序:

 

IP和端口的绑定:客户端绑定服务端的ip和端口,自己的ip及端口操作系统会自动绑定,服务端,首先 绑定自己的IP及端口,再绑定客户端的IP及端口
 

对于上面的 这个我再总结一下 ,先对这里的几个函数进行一下剖析创建套接字就不分析了,因为他的作用就是创建一个套接字描述符,套接字描述符指向一块全双工的内核缓冲区。

第二个就是我们自己定义的BIND函数,我们的传进去的参数就是服务器端的ip以及端口,这里我们的BIND函数的作用就是把自己的ip和端口和创建的套接字描述符绑定起来,原因是,我们在网络中数据的传输和发送所依靠的网卡,它负责的是端口的分配,当他拿到发送给本主机的数据之后就会把包放到对应的内核缓冲区,也就是我们创建的套接字管道里面,然后对应的进程就会从那个自己所绑定的套接字描述符所指向的管道中去拿数据。绑定这个行为我们只在服务器端进行了绑定,而没有在客户端绑定原因是,操作系统在我们创建套接字如果我们没有手动绑定的话,操作系统就会自动为我们绑定。所以客户端一般来说不需要手动绑定。

第三个就是我们自己的SEND函数,内部主要的函数是send_to系统api接口,我们主函数中传入的参数是

这几个参数,第一个参数是,外部定义的缓冲区,因为我们要发送数据就必须需要一个缓冲区来存放这些数据,是地址的原因是接口函数参数的限制,第二个是确定的IP地址,第三个是确定的端口地址,意思就是2.3参数是传入参数,这些参数是已经知道的。既然要发送就肯定知道数据是这发的。但是你发送之前还必须将这些数据转化成网络字节序,因为发送的数据要流入网络。转换完毕之后,还需要对struct sockaddr进行填充数据。

第四个就是接受数据,接收数据的参数是传入传出参数意思就是,你只是把定义好的参数地址传入,内部在接收到数据之后,就会自动解析出数据是谁发的,并且且对你传入的地址进行填充。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值