嵌入式面试准备

COW

写时复制机制(Copy On Write)可以提高进程创建效率。
子进程完整复制了父进程的地址空间,此时父子进程的虚拟内存空间映射到相同的物理内存空间。只有当二者之一执行了写入操作时才会复制写入区域的内容,为父子进程维护不同的物理页帧。

进程组

进程组ID(Process Group ID,PGID)在UNIX和类UNIX系统中用来标识一个或多个进程的集合。
进程组用于信号传递和终端控制。

会话是一个或多个进程组的集合。当用户登录到系统时,登录shell会成为一个新会话的领导。这个新会话会创建一个新的进程组,该组包含shell进程以及其子进程。

线程

线程是进程中的执行单元,它共享进程的资源和地址空间,但拥有自己的执行堆栈、程序计数器和一组寄存器。
由于线程共享相同进程内的资源,它们之间的通信和数据共享更容易。

TCP

TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,广泛应用于互联网中。
它提供可靠的端到端通信,在发送数据之前,要在两个通信端点之间建立连接。
TCP通过一系列机制确保数据的可靠传输,这些机制包括序列号、确认应答、重传控制、流量控制和拥塞控制。

面向连接
TCP是一种面向连接的协议,这意味着在数据交换之前,两个通信端必须先建立连接。这个连接通过一个三次握手(SYN、SYN-ACK、ACK)来建立,确保双方都准备好数据交换。

可靠传输
TCP通过序列号和确认应答机制确保数据的可靠传输。发送方为每个报文段分配一个序列号,接收方通过发送确认应答(ACK)来确认已经收到特定序列号的报文段。如果发送方没有在合理的超时时间内收到确认应答,它将重传该报文段。

报文段的确认号是发送方期望从对方收到的下一个字节的序号。

套接字允许不同主机上的进程通过网络进行数据交换。

套接字主要由三个属性组成:

  1. 网络地址:通常是IP地址,用于标识网络上的设备。
  2. 端口号:用于标识设备上的特定应用或进程。端口号是一个16位的数字。
  3. 协议:如TCP和UDP,定义了数据传输的规则和格式。

网络字节序和主机字节序转换

字节序指的是多字节数据在内存中的存储顺序。主要有两种字节序:

  1. 大端字节序:高位字节序存储在内存的低地址处,地位字节序存储在高地址处。这种字节序准守自然书写习惯,也被称为网络字节序,IP协议就要求使用大端字节序。
  2. 小端字节序:低位字节存储在内存的低地址处,高位字节存储在高地址处。称为主机字节序。
int net_aton(const char* cp, struct in_addr *inp);

将来自IPV4点分十进制的主机地址转换为网络字节顺序。
服务端

void *read_from_client(void *arg){
	// 使用recv接收客户端发送的数据 打印到控制台
	char* read_buf = NULL;
	int client_fd = *(int *)arg;
	read_buf = malloc(sizeof(char) * 1024);
	ssize_t count = 0;
	
	while(count = recv(client_fd, read_buf, 1024, 0)){
		fputs(readbuf, stdout);
	}

	printf("客户端请求关闭");
	free(read_buf);
	return NULL;
}

void *write_to_client(void *arg){
	//接收控制台输入的信息 发给客户
	char* write_buf = NULL;
	int client_fd = *(int *)arg;
	write_buf = malloc(sizeof(char) * 1024);
	ssize_t count = 0;

	while(fgets(write_buf, 1024, stdin) != NULL){
		send(client_fd, write_buf, 1024, 0);
	}

	printf("关闭连接");
	shutdown(client_fd, SHUT_WR);
	free(write_buf);
	return NULL;
}
int main()
{
	int sockfd, clientfd;
	pthread_t pid_read, pid_write;
	struct sockaddr_in server_addr, client_addr;
	memset(&server_addr, 0, sizeof(server_addr));
	memset(&client_addr, 0, sizeof(client_addr));

	//填写服务器地址
	server_addr.sin_family = AF_INET;
	//填写ip地址
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//inet_pton(AF_INET, "0.0.0.0", server_addr.sin_addr.s_addr);
	server_addr.sin_port = htons(6666);

	//网络编程流程
	//1、socket
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	
	//2、绑定地址
	bind(sockfd, &server_addr, sizeof(server_addr));

	//3、进入监听状态
	listen(sockfd, 1024);

	//4、获取客户端的连接,接收客户端的地址
	socklen_t clientaddr_len = sizeof(client_addr);
	// 如果调用accept之后没有客户端链接,会挂起等待
	clientfd = accept(sockfd, &client_addr, &clientaddr_len);

	printf("与客户端%s %d建立连接 文件描述符为%d", inet_ntoa(client_addr.sin_addr), inet_ntohs(client_addr.sin_port), clientfd);

	//创建子线程用于收消息
	pthread_create(&pid_read, NULL, read_from_client, (void *)clientfd);
	//创建子线程用于发消息
	pthread_create(&pid_write, NULL, write_to_client, (void *)clientfd);

	//阻塞主线程
	pthread_join(pid_read, NULL);
	pthread_join(pid_write, NULL);

	printf("释放资源\n");
	close(clientfd);
	close(sockfd);
	return 0;
}

客户端

void *read_from_server(void *arg){
	// 使用recv接收客户端发送的数据 打印到控制台
	char* read_buf = NULL;
	int client_fd = *(int *)arg;
	read_buf = malloc(sizeof(char) * 1024);
	ssize_t count = 0;
	
	while(count = recv(client_fd, read_buf, 1024, 0)){
		fputs(readbuf, stdout);
	}

	printf("服务端请求关闭");
	free(read_buf);
	return NULL;
}

void *write_to_server(void *arg){
	//接收控制台输入的信息 发给客户
	char* write_buf = NULL;
	int client_fd = *(int *)arg;
	write_buf = malloc(sizeof(char) * 1024);
	ssize_t count = 0;

	while(fgets(write_buf, 1024, stdin) != NULL){
		send(client_fd, write_buf, 1024, 0);
	}

	printf("关闭连接");
	shutdown(client_fd, SHUT_WR);
	free(write_buf);
	return NULL;
}
int main()
{
	int sockfd;
	pthread_t pid_read, pid_write;
	struct sockaddr_in server_addr, client_addr;
	memset(&server_addr, 0, sizeof(server_addr));
	memset(&client_addr, 0, sizeof(client_addr));

	//填写客户端地址
	client_addr.sin_family = AF_INET;
	//填写ip地址
	inet_pton(AF_INET, "192.168.10.150", client_addr.sin_addr.s_addr);
	client_addr.sin_port = htons(8888);

	//填写服务器地址
	server_addr.sin_family = AF_INET;
	//填写ip地址
	inet_pton(AF_INET, "127.0.0.1", server_addr.sin_addr.s_addr);
	server_addr.sin_port = htons(6666);

	//网络编程流程
	//1、socket
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	
	//2、绑定地址
	bind(sockfd, &client_addr, sizeof(client_addr));

	//3、主动连接服务端
	connect(sockfd, &server_addr, sizeof(server_addr));

	printf("连接上服务端%s %d\n", inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port));

	//创建子线程用于收消息
	pthread_create(&pid_read, NULL, read_from_server, (void *)sockfd);
	//创建子线程用于发消息
	pthread_create(&pid_write, NULL, write_to_server, (void *)sockfd);

	//阻塞主线程
	pthread_join(pid_read, NULL);
	pthread_join(pid_write, NULL);

	printf("释放资源\n");
	close(sockfd);
	return 0;
}

进程的缓存模式

进程在执行I/O操作时,可以有以下三种类型的缓冲模式。
行缓冲
在这种模式下,碰到换行符或缓冲区已满时刷写到目标文件。
行缓冲通常用于标准输出(stdout),尤其是当标准输出关联到终端(控制台)时。这样做可以确保用户每输入一行命令就能看到响应的输出,而不必等到缓冲区完全填满。

全缓冲
在全缓冲模式下,数据只会在缓冲区满时刷新,这意味着数据被存储在缓冲区直到缓冲区被填满,然后整个缓冲区的内容一次性刷写。
通常向文件写数据的默认模式就是全缓冲,这样可以减少对底层系统资源的调用次数,提高数据处理效率。

无缓冲
无缓冲模式意味着数据直接刷写,不经过缓冲区。
标准错误(stderr)通常是无缓冲的,以确保错误信息能够立即输出。

在C语言中,可以通过调用setvbuf()函数来设置文件流的缓冲模式。

UDP

服务端

char* buf = malloc(sizeof(char)*1024)
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

//服务端绑定地址
socklen_t server_len = sizeof(server_addr);
socklen_t client_len = sizeof(client_addr);
bind(sockfd, (struct sockaddr *)&server_addr, &server_len );

//收发数据
do{
	memset(buf, 0, 1024);
	recvfrom(sockfd, buf, 1024, 0, (struct client_addr*), &client_len );
	if(strncmp(buf, "EOF", 3) != 0){
		printf("%s",buf);
		strcpy(buf, "OK\N");
		sendto(sockfd, buf, 4, 0, )
	}else{
		printf("准备关闭");
	}
}while(strncmp(buf, "EOF", 3));
  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
嵌入式面试基础知识准备包括一些常见问题和答案,以及一些关于嵌入式软件开发的基础知识点。例如,关于Linux进程状态,常见的有3种状态:运行态、就绪态和等待态,而不是6种。在C语言方面,一些基础知识点包括volatile、const、static和指针等。volatile关键字通常用于多线程编程中,用于标识变量可能会被其他线程修改,需要使用该关键字来确保在编译器优化时不对这些变量进行优化。举几个需要使用volatile关键字的例子可以是多线程共享的变量或者与硬件相关的寄存器。除了这些基础知识点外,还可能涉及到其他嵌入式相关的内容,如嵌入式系统架构、设备驱动、嵌入式操作系统等。为了更好地准备嵌入式面试,建议学习这些基础知识点,并且多做一些实际的嵌入式开发项目,以增加实践经验。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [嵌入式软件面试基础知识点](https://blog.csdn.net/m0_56041246/article/details/121481340)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【嵌入式面试嵌入式知识点面经整理](https://blog.csdn.net/weixin_42112090/article/details/128686200)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

饼干饼干圆又圆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值