13.1 Linux_网络编程_TCP/UDP

字节序

1、概述

什么是字节序:

字节序就是字节的存储顺序,分为大端字节序和小端字节序。

  • 大端字节序:低地址存高位(网络)
  • 小端字节序:低地址存低位(主机)

检验主机字节序模式:

#include <stdio.h>

int main(){

	unsigned int a = 0x11223344;
	unsigned char b = *((unsigned char *)&a);

	if(b == 0x44){
		printf("小端字节序\n");
	}else{
		printf("大端字节序\n");
	}
	return 0;
}

2、字节序转换

2.1 端口号字节序转换函数

因为主机使用的是小端字节序,网络使用的是大端字节序,因此在数据传输时,需要先将数据转换为大端字节序传给网络,之后再将数据转换为小端字节序传给另一个主机。

/* h:本机 n:网络 l:32位 s:16位 */

//32位数据(4字节)
uint32_t htonl(uint32_t hostlong);//本机->网络
uint32_t ntohl(uint32_t netlong);//网络->本机
//16位数据(2字节)
uint16_t htons(uint16_t hostshort);//本机->网络
uint16_t ntohs(uint16_t netshort);//网络->本机

返回值:将小端字节序转换为大端字节序后的端口号

参数:端口号值 

2.2 IP地址字节序转换函数

该函数主要是实现点分十进制表示的IP地址转换,而不需要一个字节一个字节的去转换。

2.2.1 IPv4
//点分十进制字符串->网络字节序
in_addr_t inet_addr(const char *cp);
int inet_aton(const char *cp, struct in_addr *inp);
//网络字节序->点分十进制字符串
char *inet_ntoa(struct in_addr in);

inet_addr返回值:ip地址

cp:点分十进制字符串,例如传入"192.168.1.1"这个字符串

inp:ip地址

inet_ntoa返回值:点分十进制字符串

in:ip地址

2.2.1 IPv6
int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);

套接字socket

概述

socket多种含义:

  • 应用编程接口API:socket API,简称socket。 
  • 函数名:socket API中有一个名为socket的函数
  • 端点:比如TCP连接是有两个端点,这两个端点是一对一通信的关系。这个端点也叫socket
  • 文件描述符:socket函数的返回值是一个socket描述符,简称socket

socket的作用:

socket处在应用层与内核之间。在应用层中实现的是与应用相关的代码,在内核中实现的是网络通信相关的代码。在OSI结构中,应用层就是OSI的应用层、表示层、会话层,内核就是运输层、网络层、数据链路层、物理层。

什么是三元组:

三元组指的是IP地址、端口号、协议。该数据通过bind函数进行绑定。

  • IP地址:标识计算机,找到与网络中的哪一个计算机进行通信。
  • 端口号:标识进程,找到与计算机中哪一个进程进行通信。
  • 协议:指定数据以什么样的方式进行传递。主要指TCP、UDP

套接字的类型:

  • 流式套接字 (SOCK_STREAM) :提供可靠的、面向连接的通信流;它使用TCP,从而保证数据传输的可靠性和顺序性
  • 数据报套接字 (SOCK_DGRAM) :定义了一种不可靠、面向无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证是可靠、无差错的。它使用数据报协议UDP
  • 原始套接字(SOCK_RAW) :允许直接访问底层协议,如IP或ICMP,它功能强大但使用较为不便,主要用于协议开发。

socket文件的读写含义:

socket在Linux中也是一种文件,对socket文件进行读就是读取网络传输过来的数据,对socket文件进行写就是向网络中传输相应的数据。

相关函数 

socket相关API:

创建套接字、绑定通信结构体、监听套接字、接收套接字、发起连接

通用 

1、创建套接字
int socket(int domain, int type, int protocol);

返回值:成功返回socket文件描述符,失败返回-1

domain:指定bind中传入的地址族结构体的类型,与sa_family_t的取值要一致。

domain值 含义
AF_UNIX UNIX 域套接字地址族,用于在同一台主机上的进程间通信
AF_INET IPv4 地址族,用于 IPv4 通信
AF_INET6 IPv6 地址族,用于 IPv6 通信

type:套接字的类型,就是"概述"中的说的三种类型

type值 使用的协议
<think>好的,我现在需要解决用户在ModelSim中遇到的vlog-2110错误,涉及非法引用网络变量mod_w_req和mod_x_req。首先,我应该回顾一下用户提供的引用内容,尤其是引用[1]提到的解决方法。根据引用[1],当在always块中对信号进行赋值时,如果该信号被声明为wire类型,就会导致这个错误,因为wire类型无法在过程块中被赋值,必须改为reg类型。 接下来,我需要确认用户的问题是否属于这种情况。用户提到的是mod_w_req和mod_x_req这两个信号出现了非法引用。可能的错误原因包括:这两个信号可能在always或initial块中被赋值,但它们的声明类型是wire而不是reg。此外,还需要检查是否有其他可能的原因,比如模块端口声明是否正确,或者信号是否被多重驱动。 根据引用[1]的解决方案,用户需要检查这些信号是否在过程块中被赋值。如果是,就需要将它们声明为reg类型。但需要注意的是,在Verilog中,reg类型并不一定代表实际的寄存器,而是表示该信号在过程块中被赋值。因此,正确的做法是将这两个信号的声明从wire改为reg。 另外,还需要检查模块的端口声明是否正确。例如,如果mod_w_req和mod_x_req是模块的输出端口,那么在模块声明时应该将它们定义为reg类型,如果它们在过程块中被赋值。例如: module example ( input clk, output reg mod_w_req, // 如果需要在过程块中赋值,必须声明为reg output mod_x_req ); 但是,如果mod_x_req在过程块中被赋值,同样需要声明为reg。否则,就会出现vlog-2110错误。 此外,用户可能在组合逻辑或时序逻辑的always块中对这些信号进行了赋值,而没有正确声明为reg。比如: always @(*) begin mod_w_req = some_expression; // 如果mod_w_req是wire类型,这里会报错 end 在这种情况下,必须将mod_w_req声明为reg。 总结可能的解决步骤: 1. 找到mod_w_req和mod_x_req在代码中的声明位置,检查是否为wire类型。 2. 查看这些信号是否在always或initial块中被赋值。 3. 如果是在过程块中赋值,将它们的声明改为reg类型。 4. 检查模块端口的声明,确保输出端口如果被过程赋值,声明为reg。 5. 确保没有其他驱动冲突,例如多个always块对同一信号赋值,或者混合使用连续赋值和过程赋值。 另外,用户可能还犯了其他相关错误,比如在模块实例化时连接了错误的信号类型,或者信号名称拼写错误。但根据错误信息,主要问题还是类型声明不正确。 需要提醒用户注意Verilog中reg和wire的区别:wire用于连续赋值或模块连接,而reg用于过程赋值(always或initial块)。因此,任何在过程块中被赋值的信号必须声明为reg,无论是否实际生成寄存器。 最后,建议用户检查相关代码行,确保所有在过程块中赋值的信号都已正确声明为reg类型,并确认模块端口的声明是否匹配。</think>### 解决方案:ModelSim非法引用网络变量错误(vlog-2110) 在ModelSim中遇到`vlog-2110 Illegal reference to net "mod_w_req/mod_x_req"`错误时,通常是因为**在过程赋值语句(如`always`或`initial`块)中对未声明为`reg`类型的信号进行了赋值**。以下是具体解决步骤: --- #### **步骤1:检查信号声明类型** - **问题根源**:`mod_w_req`和`mod_x_req`默认被推断为`wire`类型,但`wire`类型无法在过程块(如`always`)中赋值[^1]。 - **解决方法**:在模块内部或端口声明中,将这两个信号显式声明为`reg`类型。 ```verilog // 错误示例:默认wire类型 output mod_w_req, mod_x_req; // 正确示例:声明为reg类型 output reg mod_w_req, mod_x_req; ``` --- #### **步骤2:检查过程块中的赋值语句** - **关键点**:确保所有在`always`或`initial`块中被赋值的信号均声明为`reg`。 ```verilog always @(posedge clk) begin mod_w_req <= ... ; // 若mod_w_req未声明为reg,会报错 end ``` --- #### **步骤3:验证端口方向与类型匹配** - **常见问题**:若信号是模块的输出端口,需在模块定义时声明为`output reg`而非`output wire`。 ```verilog module example ( input clk, output reg mod_w_req, // 正确声明 output reg mod_x_req ); ``` --- #### **步骤4:检查多重驱动或信号冲突** - **附加建议**:确保同一信号未被多个`always`块或连续赋值语句(`assign`)同时驱动,否则可能导致竞争条件或综合错误。 --- ### 相关问题 1. **如何区分Verilog中的`reg`和`wire`类型?** `wire`用于连续赋值或模块间连接,`reg`用于过程赋值(如`always`块)。 2. **ModelSim报错`Unresolved reference to 'GRS_INST'`如何解决?** 需检查仿真库是否包含缺失的模块,例如在紫光PDS中需链接GRS相关库文件[^3]。 3. **如何处理`Failed to open design unit file`错误?** 确保文件路径正确且文件名无拼写错误,必要时重新编译依赖模块[^2]。 : 非法引用网络变量错误需将过程赋值信号声明为`reg`类型 : 文件未找到错误需检查路径和编译顺序 [^3]: 缺少库引用需配置仿真环境链接对应库文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值