网络编程(套接字)

目录

一、套接字

1、套接字的作用

2、关于TCP和UDP协议

[1. TCP协议](#1. TCP协议)

[2. UDP协议](#2. UDP协议)

[3. 两者的区别](#3. 两者的区别)

2、套接字函数

[1)函数 socket(创建套接字同文件描述符)](#1)函数 socket(创建套接字同文件描述符))

2)准备套接字用结构体

[1. 套接字的结构体](#1. 套接字的结构体)

[2. 客户端的套接字:](#2. 客户端的套接字:)

[3. 服务器的套接字:](#3. 服务器的套接字:)

[3)bind(以结构体向套接字中写入 ip、port)](#3)bind(以结构体向套接字中写入 ip、port))

[4)send / write(通过套接字发送数据)](#4)send / write(通过套接字发送数据))

[5)recv / read(通过套接字接收数据)](#5)recv / read(通过套接字接收数据))

6)fcntl(变更函数状态:阻塞/非阻塞)


一、套接字

套接字在最初只是一种IPC通讯手段,在TCP协议出现,TCP协议使用套接字进行通信,因此我们常说的套接字都是应用于网络通信,而早期只用于进程间通讯的则称为域套接字

1、套接字的作用

专门用于网络间通信的一种文件形式

该文件,包含了要交换的数据和通信双方的 ip地址和 port端口号

ip地址和 port端口号需要我们自己添加到套接字中,并且不同的协议需要使用不同类型的套接字

2、关于TCP和UDP协议

TCP协议和UDP协议的套接字就是不同类型的

1. TCP协议

TCP协议是一个可靠的,连续的,基于字节流的协议,TCP具有流量控制功能,顺序控制功能,应答重发功能,以确保在网络不拥堵的时候,所有的数据都可以正确的发送

2. UDP协议

UDP协议由于非连续性,且没有有效的应答手段,所以不可靠,很容易丢包

向前纠错技术(后来各大厂商对UDP协议的更进,添加了校验的方法)

udp协议在发送数据的时候,会选择在发送 n 个数据的时候,匹配发送 m 个校验包

比如说发送 3个数据的时候,匹配发送1个校验包

最简单的校验包 = 1#数据报 + 2#数据报 + 3#数据报

比如说:发送了 1 ,2,3 这3个数据,此时,再发送一个校验包,校验包的值是 4

很明显,在丢包率为 25% 的时候,3个包配一个校验包,就能完全避免丢包

因为4个包里面丢一个,丢了校验包完全无所谓

丢的是任意一个数据包,可以通过校验包和其他数据包,恢复出丢失的数据是多少

依此类推:如果网络波动变大,我们就需要配更多的校验包,以保证丢包率减低,恢复率提高

3. 两者的区别

TCP协议稳定性高,传输速度慢,UDP协议稳定性差,传输速度快

2、套接字函数

1)函数 socket(创建套接字同文件描述符)

cs 复制代码
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:创建不同类型的套接字用文件描述符
参数 domain:套接字所依赖的网络介质
    如果是 ipv4 就填入 AF_INET
    如果是 ipv6 就填入 AF_INET6
    如果是 域套接字 就填入 AF_LOCAL / AF_UNIX
参数 type:选择套接字的类型
    SCOK_STREAM:字节流套接字传输数据,连续,可靠,双向,数据量大
    SOCL_DGRAM:数据包套接字传输数据,不连续,不可靠,有长度要求,双向
参数 protocol:选择套接字所依赖的通信协议
    0:自动匹配,会根据参数 type 和参数 protocol 自动选择合适的通信协议
返回值:
    返回创建套接字文件描述符

一般来说:
    AF_INET + SOCK_STREAM + 0 ,最终创建的是 TCP 协议的套接字
    AF_INET + SOCK_DGRAM  + 0 ,最终创建的是 UDP 协议的套接字 

字节流的优点:允许发送无穷大的数据,会在内核中对数据做分割处理,但是由于连续发送,数据依然粘连在一起

字节流的缺点:由于数据是粘连的,因此接收端需要花费大量的时间处理数据

数据包的优点:数据不会粘连,发送几次数据就是几个数据包

数据包的缺点:发送的数据大小有上限,过大的数据需要手动分批次发送,还有丢包的风险

2)准备套接字用结构体

1. 套接字的结构体
cs 复制代码
struct sockaddr_in {
  __kernel_sa_family_t  sin_family; /* 依赖的网络介质       */
  __be16        sin_port;           /* port端口号           */
  struct in_addr    sin_addr;       /* ip地址               */
};

127.0.0.1 是一个本地回环地址,不会经过网卡,专门用来在无网络的情况下做本地测试,

抓包工具无法抓到这个 ip地址 的数据

2. 客户端的套接字:

写入 ip地址 的目的 是为了通过 ip地址,找到该客户端想要连接的服务器

写入 port端口号 的目的 是为了通过端口号,知道数据需要发送到服务器的哪个进程

3. 服务器的套接字:

写入 ip地址 的目的 是过滤掉不想接收的客户端,选择想要连接的客户端

写入 port端口号 的目的 是为了让服务器知道要去哪个进程读取接收到的数据

3)bind(以结构体向套接字中写入 ip、port)

cs 复制代码
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:往套接字中写入 ip地址 和 port端口号 (该操作被称为为套接字命名)
参数 sockfd:填写 套接字用文件描述法
参数 addr:通用套接字结构体指针,需要提前准备 struct sockaddr_in 类型的结构体
参数 addrlen:参数 addr 的字节长度

4)send / write(通过套接字发送数据)

cs 复制代码
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:通过套接字,向套接字中指向的ip地址发送数据
参数 sockfd:填入 socket创建的套接字文件描述符
参数 buf:填入 要发送的数据的地址
参数 len:填入 要发送的字节的长度
参数 flag:设置函数的状态 阻塞 / 非阻塞
    0    :默认阻塞,发送数据给目标,目标的接收区满了,就会发送阻塞
    MSG_DONTWAIT:非阻塞,发送数据给目标,接收区满了,丢弃新发送的数据
=======================================================================
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
用法基本一致,IO篇也有详细介绍

5)recv / read(通过套接字接收数据)

cs 复制代码
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:通过套接字,读取套接字中ip地址所发送的数据
参数 sockfd:由socket创建的套接字文件描述符
参数 buf:将读取到的数据存入buf所指向的连续地址(所指向的数组)
参数 len:所读取数据的字节长度
参数 flags:设置函数的状态 阻塞 / 非阻塞
    0    :默认阻塞,没有接收到数据就阻塞
    MSG_DONTWAIT:非阻塞,没有读取到数据直接返回 0 
返回值:
    阻塞模式:
        返回接收到数据的字节数,若套接字损坏 返回 -1
        若服务器与客户端连接断开,则有阻塞函数变为非阻塞函数,并返回 0
    非阻塞模式:
        返回接收到数据的字节数,若服务器与客户端断开,返回 -1
        未接收到参数,则返回 0
=====================================================================
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
用法基本一致,IO篇也有详细介绍

6)fcntl(变更函数状态:阻塞/非阻塞)

cs 复制代码
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
功能:设置指定文件描述符的状态,也就是flags属性
参数 cmd:设置函数的功能 设置 flags 或 读取 flags
    F_SETFL:设置 fd 文件的 flags 属性
    F_GETFL:获取 fd 文件的 flags 属性
不定参 ···:此处只有第一个数据是有效的
    仅当 cmd == F_SETFL 时,需要传一个不定参作为 flags
返回值:
    当 cmd == F_SETFL 时,成功返回 0 ,失败返回 -1
    当 cmd == F_GETFL 时,返回 flags ,失败返回 -1

使用时要注意不要变更原有的状态,因此尽可能追加flags值(若有需要替换原先的值,也可以换)

使用流程:

1、先获取 fd 原有的 flags 属性

2、对获取到的 flags 属性追加

3、将追加好的 flags 属性,设置为 fd 的 flags 属性

以标准输入流为例

相关推荐
码头薯条Pro1 小时前
Javaweb使用websocket,请先连上demo好吧!很简单的!
网络·websocket·网络协议
fjhcom1 小时前
PDXP、UDP与HDLC协议技术解析:架构、应用与对比研究
网络·网络协议
Lo-Y-eH1 小时前
HTTP 四种常见方法
网络·网络协议·http
hjh198292 小时前
渗透前四天总结
网络·网络安全
电信2301杨臣3 小时前
Imx6ull用网线与电脑连接
运维·服务器·网络
꧁༺△再临ཊ࿈ཏTSC△༻꧂5 小时前
The Backrooms Level0“教学关卡”
网络
FreeBuf_13 小时前
黄金旋律IAB组织利用暴露的ASP.NET机器密钥实施未授权访问
网络·后端·asp.net
Tanecious.14 小时前
C++--红黑树封装实现set和map
网络·c++
帽儿山的枪手15 小时前
追踪网络流量就这么简单 | 进阶篇 | conntrack
linux·windows·网络协议