c语言网络编程
1、TCP和UDP的区别
相同点:都是传输层的协议。都是全双工通讯。
TCP:
- 面向连接:端到端的连接。在传输数据之前必须建立连接。数据传输之后要释放连接。
- TCP基于字节流的数据传输:完整的用户消息可能拆分成多个tcp报文进行传输。对于接收方需要进行粘包。
- TCP可靠传输:TCP会进行发送数据包的控制。流量控制、拥塞控制、重传机制。
- 适用场景:适用于需要可靠传输的应用,如网页浏览,文件传输等。
UDP:
- 无连接:支持一对多和多对一的通讯方式。无需建立连接即可发送数据包。
- UDP是基于报文的传输方式:UDP每次发送的都是完整的报文。
- UDP不保证可靠性:不提供确认机制,不保证数据包的顺序,大量数据可能丢失或重复;
- 适用于实时应用,如直播、语音、游戏等。
传输效率:TCP头部20字节、udp头部8字节
TCP头部主要关注的信息
- 源端口号和目标端口号:标识数据来自于哪个程序要发送给哪个程序。
- 序列号:用于标识发送字节流的顺序。
- 确认号:表示期望接收下一个字节的序列号。
- 数据偏移:指示TCP头部的长度,以32位字为单位,用于确定数据部分的其实位置。
- 控制位:包含多个标志位,其中比较重要的就是SYN、ACK、FIN、RST、URG
- 窗口大小:表示接收方的缓冲区大小,用于流量控制。
- 校验和:用于错误检测,接收方接收完数据后计算校验和与接收的校验和比较。
- 紧急指针:用于指示紧急数据的结束位置。
- 选项字段:加上选择和填充字段后TCP报文头最大可达60字节。
2、什么是TCP粘包?
- TCP粘包就是指发送方发送的若干数据包到达接收方时粘成了一个包。从接收缓冲区
来看,后一包数据的头紧接着前一包数据的尾。 - 为什么要粘包: TCP是面向字节流的协议,TCP将数据看作一个连续的字节流,而不是独立的消息。因此,发送的数据可能在接收端被合并。
3、如何处理粘包问题?
- 发送方:发送方可以使用TCP_nodelay关闭nagle算发;
- 接收方:接收方没法处理,交给应用层处理;
- 应用层:①格式化数据使用固定的分隔符标识不同的数据包;②规定每个数据包的长度是固定的,接收方可以根据这个长度来读取数据。③在每个数据包前添加一个固定长度的消息头,消息头中包含数据包的长度信息。
4、IP地址与MAC地址的相同点和不同点?
- 相同点:都是唯一的。
- 不同点:
- IP地址是根据网络拓扑设计的可以改动。MAC地址是基于制造商出厂设定的一般不能修改。
- 长度:IP地址是32位,MAC地址是48位。
- 寻址协议不同:IP地址用于网络层。网络层协议可以使数据从一个网络传递到另一个网络。MAC地址用于数据链路层。数据链路层协议可以使数据从一个节点传递到另一个节点。
5、路由器、交换机、集线器的区别?
- 路由器工作在网络层,根据网络层提供的IP选择路由。
- 交互器工作在数据链路层,通过数据链路层提供的MAC地址选择端口。
- 集线器工作在物理层,只对信号进行整形、放大再发广播。
6、socket编程中常用的函数
int socket(int domain,int type,int protocol)
- 通讯协议族:
- AF_INET:IPv4 地址族
- AF_INET6::IPv6 地址族
- 数据类型 :
- SOCK_STREAM:提供可靠的、面向连接的字节流服务,通常用于 TCP 协议。
- SOCK_DGRAM:提供无连接的数据报服务,通常用于 UDP 协议。
- 最终使用的协议:
- IPPROTO_TCP:TCP传输协议
- IPPTOTO_UDP:UDP传输协议
- 一般可设置为0使用默认值
- 返回值
如果socket()函数成功,它返回一个非负整数,即新创建的套接字的文件描述符。这个文件描述符在后续的网络操作中用于标识和操作该套接字。
- 通讯协议族:
int bind(int sockfd,const struct socket *addr,socklen_t addrlen)
- sockfd:为socket()函数返回的sock标志符
- addr:为一个指向socketaddr的结构指针,该结构体中包含了要绑定的IP和端口号
- addrlen:addr所指向结构体的长度,通常使用sizeof(struct sockaddr_in)来获取。
- 返回值:成功返回0,否则返回-1
int listen(int sockfd, int backlog)
- sockfd:需要设置成监听模式的套接字的描述符,他需要是完成绑定IP和端口的套接字。
- backlog:请求队列的最大长度(能存放多少个客户端的请求)
- 返回值:成功返回0,失败返回-1;
int accept(int sockfd,struct socket *addr,socklen_t *addrlen)
- socket:为通过socket()创建并通过bind()和listen()初始化的套接字。
- addr:指向sockaddr结构体的指针,用于存储客户端的信息,如果不需要获取客户的信息,这个值可以设置为0
- addrlen:这是一个指向socklen_t类型变量的指针,它用于传入addr结构体的大小,并在调用后返回实际客户端地址的大小。如果addr设置为NULL,则addrlen也应该设置为NULL。
int connect(int socket,const struct sockaddr *serv_addr,socklen_t addrlen)
- sockfd:这是一个套接字描述符,标识了要用于连接的本地端点套接字。
- serv_addr:这是一个指向sockaddr结构的指针,该结构包含了目标服务器的地址信息。通常使用sockaddr_in结构和sockaddr_in6结构。
- addrlen:这是serv_addr指针指向的sockaddr结构的长度,通常通过sizeof()函数得到。
- 返回值:成功返回0失败返回-1
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
- sockfd:这是套接字描述符,标识了发送数据的套接字。
- buf:这是一个指向要发送数据的缓冲区的指针。
- len:这是要发送数据的字节数。
- flags:这是控制发送操作的标志位。通常设置为 0,但可以使用特定于协议的标志(如MSG_DONTWATTMSG_OOB等)。一般设置为0。
- 返回值:成功返回0,失败返回-1
ssize_t recv(int sockfd, void *buf, size_t len, int flags)
- sockfd:接收数据的套接字的文件描述符。
- buf:指向缓冲区的指针,该缓冲区用于存储接收到的数据。
- len:接收的最大字节数。
- flags:这是一组标志,用于修改接收操作的行为。常用的标志包括MSG_WAITALL(等待直到接收到完整的消息)和MSG_DONWAIT(非阻塞接收)。一般设置为0。
int close(int sockfd)
- 如果成功,返回 0。
- 如果失败,返回 -1 并设置全局变量errno以指示错误。
以太网帧的结构
以太网帧结构主要分为以下几个部分:
-
前导码 (Preamble): 7字节
- 用于同步,帮助接收方识别帧的开始。
-
帧开始定界符 (Start Frame Delimiter, SFD): 1字节
- 标识帧的开始,通常为0xAB。
-
目标MAC地址 (Destination MAC Address): 6字节
- 表示帧的接收者的MAC地址。
-
源MAC地址 (Source MAC Address): 6字节
- 表示帧的发送者的MAC地址。
-
类型/长度字段 (Type/Length): 2字节
- 指示上层协议类型(如IPv4、IPv6等)或数据长度。
-
数据负载 (Data): 46-1500字节
- 实际传输的数据,可以是各种协议的数据。
-
填充 (Padding): 0-46字节
- 如果数据负载小于46字节,将填充到46字节。
-
循环冗余校验 (CRC): 4字节
- 用于错误检测,确保数据在传输过程中没有损坏。
总体结构
以太网帧的最小长度为64字节(包括所有字段),最大长度为1518字节(对于标准以太网帧)。对于某些扩展的以太网帧(如VLAN帧),最大长度可以达到1522字节。