linux-并发通信

一.linux-tcp通信框架

1.基础框架

1.1 tcp 服务器框架

1.套接字
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
 

返回的文件描述符可以指向当前的socket,后续通过对文件描述符的访问就可以配置这个socket 

成功时返回文件描述符,失败时返回-1。

●domain 套接字中使用的协议族(ProtocolFamily)信息。

●type 套接字数据传输类型信息。((SOCK_STREAM)---TCP,(SOCKDGRAM)---UDP)

●protocol 计算机间通信中使用的协议信息。  

2.bind 函数

如果把套接字比喻为电话,那么创建套接字只安装了电话机。 接着就要给电话机分配号码的方法,即给套接字分配 IP地址和端口号。就是用的bind函数。 

#include<sys/socket.h>
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);

参数一:套接字描述符 sockfd 要分配地址信息(IP地址和端口号)的套接字文件描述符。

参数二:myaddr 存有地址信息的结构体变量地址值 

struct sockaddr   
{  unsigned short sa_family;    //2 char sa_data[14];     //14
};  
struct in_addr
{In_addr_t s_addr; //32 位 IPv4 地址
};struct sockaddr_in{sa_family//地址族(Address Family)sa_family_t sin_family;// //地址族(Address Family)uint16_t sin_port; // 16 位 TCP/UDP 端口号struct in_addr sin_addr; //32 位 IP 地址char sin_zero[8]; //不使用
}

这里我们使用scokaddr_in来配置端口和ip(参数填写更方便),然后转换为socketadrr就行,两个结构体可以互相转换的

参数三:第二个结构体变量的长度

示例配置如下:

struct sockaddr_in addr;
char* serv_ip="211.217.168.13";//声明 IP地址字符串
char * serv_port="9198"; //声明端口号字符串
memset(&addr,0,sizeof(addr);//结构体变量 addr 的所有成员初始化为 0//指定地址族
addr.sin_family =AF_INET;//基于字符串的IP地址初始化
//inet用于将点分十进制的IP地址字符串转换成网络字节顺序(big-endian)的整数表示形式。
addr.sin_addr.s_addr=inet_addr(serv_ip);//基于字符串的端口号初始化
//atoi字符型转换为整型
addr.sin_port=htons(atoi(serv_port));
3.listen 函数:
#include <sys/socket.h>
int listen(int sock,int backlog);

sock 希望进入等待连接请求状态的套接字文件描述符

  • 传递的描述符套接字参数成为服务器端 套接字(监听套接字)。
  • backlog 连接请求等待队列(Queue)的长度,若为5,则队列长度为5,表示最多使5个连 接请求进入队列。
 4.accept 函数:
#include<sys/socket.h>
int accept(int sock,struct sockaddr * addr, socklen_t*addrlen);

成功时返回创建的套接字文件描述符,失败时返回-1。

  • 参数sock:服务器套接字的文件描述符。
  • 参数addr:保存发起连接请求的客户端地址信息的变量地址值,调用函数后向传递来的地址变量参数填充客户端地址信息。
  • 参数addrlen:第二个参数结构体的长度,但是存有长度的变量地址。函数调用完成后,该变量即被填客户端地址长度

 accept 函数受理连接请求等待队列中待处理的客户端连接请求。函数调用成功时,accept函数内部将产生用于数据I/O的套接字,并返回其文件描述符。套接字是自动创建的,并自 动与发起连接请求的客户端建立连接。上图展示了accept函数调用过程。

5. tcp 服务端框架
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>int main(){int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;  
/*
在网络编程中,一个服务器可能有多个网络接口(即多个IP地址)。如果你指定了一个具体的
IP地址来绑socket,那么服务器程序只能接受发送到这个特定IP地址的连接请求。相反,
使用INADDR_ANY可以让服务接受到达服务器上任何网络接口的连接请求,
这样就不需要针对每个可能的IP地址分别设置监听了。
*/serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  serv_addr.sin_port = htons(9190);  bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));listen(serv_sock, 20);
//用于生成客户端套接字,中间需要使用一个addr结构体,我们创建一个空结构体传入
accept辅助完成socket创建struct sockaddr_in clnt_addr;socklen_t clnt_addr_size = sizeof(clnt_addr);
//accept后会创建一个套接字,int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);char message[] = "Hello, World!";write(clnt_sock, message, sizeof(message));close(clnt_sock);  close(serv_sock);  return 0;
}

1.2 tcp 客户端框架

1.connect
#include<sys/socket.h>
int connect(int sock,struct sockaddr*servaddr, socklen_t addrlen);

成功时返回0,失败时返回-1。

  • sock 客户端套接字文件描述符。
  • servaddr 保存目标服务器端地址信息的变量地址值。
  • addrlen 以字节为单位传递给第二个结构体参数servaddr的地址变量长度
2.客户端框架 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>int main(){int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);struct sockaddr_in serv_addr;memset(&serv_addr, 0, sizeof(serv_addr));  serv_addr.sin_family = AF_INET;  serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  serv_addr.sin_port = htons(9190);  
//connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));char buffer[40];read(sock, buffer, sizeof(buffer)-1);printf("Message from server: %s\n", buffer);close(sock);return 0;
}

1.3 线程基础

1.线程创建
#include<pthread.h>
int pthread_create(pthread_t*restrict thread,const pthread_attr_t * restrict attr,void *(* start_routine)(void *),void*restrict arg
);

成功时返回 0,失败时返回其他值。

●thread:保存新创建线程ID的变量地址值。线程与进程相同,也需要用于区分不同线程的ID。

attr:用于传递线程属性的参数,传递NULL时,创建默认属性的线程。

start_routine:相当于线程main函数的、在单独执行流中执行的函数地址值(函数指针)。

arg:通过第三个参数传递调用函数时包含传递参数信息的变量地址值。

#include<pthread.h>
int pthread_join(pthread_t thread, void ** status);

 调用pthread_join 函数的进程(或线程)将进入等待状态,直到第一个参数为ID的线程终 止为止。而且可以得到线程的main函数返回值,所以该函数比较有用。下面通过示例了解 该函数的功能。

成功时返回e,失败时返回其他值。

  • thread 该参数值ID的线程终止后才会从该函数返回。
  • status保存线程的main函数返回值的 指针变量地址值。
2.互斥锁
#include<pthread.h>
int pthread_mutex_init(pthread mutex_t*mutex, const pthread_mutexattr_t* attr);
int pthread_mutex_destroy(pthread_mutex_t * mutex);
  • mutex 创建互斥量时传递保存互斥量的变量地址值,销毁时传递需要销毁的互斥量地址值。
  • attr传递即将创建的互斥量属性,没有特别需要指定的属性时传递NULL。
#include<pthread.h>
int pthread_mutex_lock(pthread_mutex_t* mutex);
int pthread_mutex_unlock(pthread mutex_t* mutex);

成功时返回0,失败时返回其他值。

使用方法:

pthread_mutex_lock(&mutex);//临界区的开始
//.....// 临界区的结束
pthreadmutex_unlock(&mutex);

线程使用实例:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>// 全局变量作为共享资源
int shared_resource = 0;
// 互斥量对象
pthread_mutex_t mutex;// 线程函数,递增共享资源
void* thread_func(void* arg) {for(int i = 0; i < 10000; ++i) {// 锁定互斥量pthread_mutex_lock(&mutex);// 访问并修改共享资源shared_resource++;// 解锁互斥量pthread_mutex_unlock(&mutex);}return NULL;
}int main() {pthread_t thread1, thread2;// 初始化互斥量pthread_mutex_init(&mutex, NULL);// 创建两个线程pthread_create(&thread1, NULL, thread_func, NULL);pthread_create(&thread2, NULL, thread_func, NULL);// 等待线程结束pthread_join(thread1, NULL);pthread_join(thread2, NULL);// 打印共享资源的最终值printf("Final value of shared resource: %d\n", shared_resource);// 销毁互斥量pthread_mutex_destroy(&mutex);return 0;
}

二、并发服务器

2.1 多线程服务器实现

1.服务器端:

每次accept都阻塞,来一个连接,就创建一个线程进行处理,多线程互不干扰 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#define BUF_SIZE 100
#define MAX_CLNT 256
void* handle_clnt(void* arg);
void send_msg(char* msg, int len);
void error_handling(char* msg);
int clnt_cnt = 0;
int clnt_socks[MAX_CLNT];
pthread_mutex_t mutx;
int main(int argc, char* argv[])
{int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;int clnt_adr_sz;pthread_t t_id;if (argc != 2) {printf("Usage : %s <port>\n", argv[0]);exit(1);}pthread_mutex_init(&mutx, NULL);serv_sock = socket(PF_INET, SOCK_STREAM, 0);memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);serv_adr.sin_port = htons(atoi(argv[1]));if (bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)error_handling("bind() error");if (listen(serv_sock, 5) == -1)error_handling("listen() error");while (1){clnt_adr_sz = sizeof(clnt_adr);clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);pthread_mutex_lock(&mutx);clnt_socks[clnt_cnt++] = clnt_sock;pthread_mutex_unlock(&mutx);pthread_create(&t_id, NULL, handle_clnt, (void*)&clnt_sock);pthread_detach(t_id);printf("Connected client IP: %s \n", inet_ntoa(clnt_adr.sin_addr));}close(serv_sock);return 0;
}
void* handle_clnt(void* arg)
{int clnt_sock = *((int*)arg);int str_len = 0, i;char msg[BUF_SIZE];while ((str_len = read(clnt_sock, msg, sizeof(msg))) != 0)send_msg(msg, str_len);pthread_mutex_lock(&mutx);for (i = 0; i < clnt_cnt; i++)// remove disconnected client{}if (clnt_sock == clnt_socks[i]){while (i++ < clnt_cnt - 1)clnt_socks[i] = clnt_socks[i + 1];break;}clnt_cnt--;pthread_mutex_unlock(&mutx);close(clnt_sock);return NULL;
}
void send_msg(char* msg, int len)
{int i;// send to allpthread_mutex_lock(&mutx);for (i = 0; i < clnt_cnt; i++)write(clnt_socks[i], msg, len);pthread_mutex_unlock(&mutx);
}
void error_handling(char* msg)
{fputs(msg, stderr);fputc('\n', stderr);exit(1);
}

2.客户端:

一个主线程即可

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#define BUF_SIZE 100
#define NAME_SIZE 20
void* send_msg(void* arg);
void* recv_msg(void* arg);
void error_handling(char* msg);
char name[NAME_SIZE] = "[DEFAULT]";
char msg[BUF_SIZE];
int main(int argc, char* argv[])
{int sock;struct sockaddr_in serv_addr;pthread_t snd_thread, rcv_thread;void* thread_return;if (argc != 4) {printf("Usage : %s <IP> <port> <name>\n", argv[0]);exit(1);}sprintf(name, "[%s]", argv[3]);sock = socket(PF_INET, SOCK_STREAM, 0);memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = inet_addr(argv[1]);serv_addr.sin_port = htons(atoi(argv[2]));if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)error_handling("connect() error");pthread_create(&snd_thread, NULL, send_msg, (void*)&sock);pthread_create(&rcv_thread, NULL, recv_msg, (void*)&sock);pthread_join(snd_thread, &thread_return);pthread_join(rcv_thread, &thread_return);close(sock);return 0;
}
void* send_msg(void* arg)
{int sock = *((int*)arg);// send thread mainchar name_msg[NAME_SIZE + BUF_SIZE];while (1){}fgets(msg, BUF_SIZE, stdin);if (!strcmp(msg, "q\n") || !strcmp(msg, "Q\n")){close(sock);exit(0);}sprintf(name_msg, "%s %s", name, msg);write(sock, name_msg, strlen(name_msg));return NULL;
}
void* recv_msg(void* arg)
{int sock = *((int*)arg);// read thread mainchar name_msg[NAME_SIZE + BUF_SIZE];int str_len;while (1){str_len = read(sock, name_msg, NAME_SIZE + BUF_SIZE - 1);if (str_len == -1)return (void*)-1;name_msg[str_len] = 0;fputs(name_msg, stdout);}return NULL;
}
void error_handling(char* msg)
{fputs(msg, stderr);fputc('\n', stderr);exit(1);
}

2.2 select 多路io复用实现

1. 原理及步骤

 文件描述符:

一开始默认是空的,当我们创建socket或者文件时,就会从3开始分配文件描述符给相应的socket或者文件

2.select 函数 与fd_set

select: 

#include<sys/select.h>#include <sys/time.h>
int select(int maxfd, fd_set*readset, fd_set* writeset, fd_set*exceptset, const struct
timeval * timeout);

成功时返回大于0的值,失败时返回-1。

  • maxtfd :监视对象文件描述符数量
  • readset:用于检查可读性
  • writeset:用于检查可写性
  • exceptset:用于检查带外数据
  • timeout:一个指向timeval 结构的指针,用于决定select等待I/O的最长时间。如果为空将 一直等待。

fd_set结构体:

作用:用于表示一组文件描述符的集合,不要和文件描述符结构混淆

  • FD_ZERO(fdset*fdset)∶将 fdset 变量的所有位初始化为0。
  • FD_SET(int fd,fd set*fdset)∶在参数 fdset 指向的变量中注册文件描述符fd的信息。
  • FD_CLR(int fd,fdset*fdset)∶从参数 fdset 指向的变量中清除文件描述符fd的信息。
  • FD_ISSET(int fd,fd_set*fdset)∶若参数 fdset 指向的变量中包含文件描述符fd的信息,则 返回"真"。

3.select实现并发服务器 

主要步骤: 

1.由于serv_sock是最开始创建的,那么它一定是最大的文件描述符,且只创建了 serv_sock,我们将这个文件描述符添加到fd_map中(具有能够被select监听的资格,但这个监听和listen不是一个东西,如果相应文件描述符表示的sock有动作,那么select就会结束阻塞,开始后面的工作):

	FD_ZERO(&reads);FD_SET(serv_sock, &reads);fd_max = serv_sock;

2. 进入循环,我们将当前的所有得到的文件描述符都放入进行监听

if ((fd_num = select(fd_max + 1, &cpy_reads, 0, 0, &timeout)) == -1)break;
if (fd_num == 0)continue;

 3.遍历到最大文件描述符,通过FD_SET来判断哪些文件描述符是被激活的(导致select不阻塞的),同时记得处理时,要把这个文件描述符clear掉

for (i = 0; i < fd_max + 1; i++){if (FD_ISSET(i, &cpy_reads)){if (i == serv_sock){// connection request!adr_sz = sizeof(clnt_adr);clnt_sock =accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);FD_SET(clnt_sock, &reads);if (fd_max < clnt_sock)fd_max = clnt_sock;printf("connected client: %d \n", clnt_sock);}else{// read message!str_len = read(i, buf, BUF_SIZE);if (str_len == 0)// close request!{FD_CLR(i, &reads);close(i);printf("closed client: %d \n", i);}else{}}write(i, buf, str_len);}}

完整代码如下: 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#define BUF_SIZE 100
void error_handling(char* buf);
int main(int argc, char* argv[])
{int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;struct timeval timeout;fd_set reads, cpy_reads;socklen_t adr_sz;int fd_max, str_len, fd_num, i;char buf[BUF_SIZE];if (argc != 2) {printf("Usage : %s <port>\n", argv[0]);exit(1);}serv_sock = socket(PF_INET, SOCK_STREAM, 0);memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);serv_adr.sin_port = htons(atoi(argv[1]));if (bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)error_handling("bind() error");if (listen(serv_sock, 5) == -1)error_handling("listen() error");FD_ZERO(&reads);FD_SET(serv_sock, &reads);fd_max = serv_sock;while (1){cpy_reads = reads;timeout.tv_sec = 5;timeout.tv_usec = 5000;if ((fd_num = select(fd_max + 1, &cpy_reads, 0, 0, &timeout)) == -1)break;if (fd_num == 0)continue;for (i = 0; i < fd_max + 1; i++){if (FD_ISSET(i, &cpy_reads)){if (i == serv_sock){// connection request!adr_sz = sizeof(clnt_adr);clnt_sock =accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);FD_SET(clnt_sock, &reads);if (fd_max < clnt_sock)fd_max = clnt_sock;printf("connected client: %d \n", clnt_sock);}else{// read message!str_len = read(i, buf, BUF_SIZE);// close request!if (str_len == 0){FD_CLR(i, &reads);close(i);printf("closed client: %d \n", i);}else{write(i, buf, str_len);}}}}}close(serv_sock);return 0;
}
void error_handling(char* buf)
{fputs(buf, stderr);fputc('\n', stderr);exit(1);
}

4.客户端

客户端代码和一般客户端无异: 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char* message);
int main(int argc, char* argv[])
{int sock;char message[BUF_SIZE];int str_len;struct sockaddr_in serv_adr;if (argc != 3) {printf("Usage : %s <IP> <port>\n", argv[0]);exit(1);}sock = socket(PF_INET, SOCK_STREAM, 0);if (sock == -1)error_handling("socket() error");memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = inet_addr(argv[1]);serv_adr.sin_port = htons(atoi(argv[2]));if (connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)error_handling("connect() error!");elseputs("Connected...........");while (1){fputs("Input message(Q to quit): ", stdout);fgets(message, BUF_SIZE, stdin);if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))break;write(sock, message, strlen(message));str_len = read(sock, message, BUF_SIZE - 1);message[str_len] = 0;printf("Message from server: %s", message);}close(sock);return 0;
}
void error_handling(char* message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/702950.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nccl2安装指南

https://developer.nvidia.com/nccl/nccl-download 旧版本安装: https://developer.nvidia.com/nccl/nccl-legacy-downloads 找到你对应的CUDA版本 我这里选择 deb 文件安装了 sudo dpkg -i nccl-local-repo-ubuntu2004-2.16.5-cuda11.8_1.0-1_amd64.debsudo cp /var/nccl-lo…

使用 React 和 MUI 创建多选 Checkbox 树组件

在本篇博客中&#xff0c;我们将使用 React 和 MUI&#xff08;Material-UI&#xff09;库来创建一个多选 Checkbox 树组件。该组件可以用于展示树形结构的数据&#xff0c;并允许用户选择多个节点。 前提 在开始之前&#xff0c;确保你已经安装了以下依赖&#xff1a; Reac…

政安晨:【机器学习基础】(二)—— 评估机器学习模型改进

根据前面我的文章看来&#xff0c;咱们只能控制可以观察到的东西。因为您的目标是开发出能够成功泛化到新数据的模型&#xff0c;所以能够可靠地衡量模型泛化能力是至关重要的&#xff0c;咱们这篇文章将正式介绍评估机器学习模型的各种方法。 政安晨的个人主页&#xff1a;政安…

Hikvision SPON IP网络对讲广播系统命令执行漏洞

声明 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 1.漏洞描述 Hikvision Intercom Broadcasting System是中国海康威视&a…

低功耗设计——门控时钟

1. 前言 芯片功耗组成中&#xff0c;有高达40%甚至更多是由时钟树消耗掉的。这个结果的原因也很直观&#xff0c;因为这些时钟树在系统中具有最高的切换频率&#xff0c;而且有很多时钟buffer&#xff0c;而且为了最小化时钟延时&#xff0c;它们通常具有很高的驱动强度。此外&…

leetcode hot100 买卖股票最佳时机3

本题中&#xff0c;依旧可以采用动态规划来进行解决&#xff0c;之前的两个题我们都是用二维数组dp[i][2]来表示的&#xff0c;其中i表示第i天&#xff0c;2表示长度为2&#xff0c;其中0表示不持有&#xff0c;1表示持有。 本题中&#xff0c;说至多完成两笔交易&#xff0c;也…

力扣--动态规划1027.最长等差数列

思路分析&#xff1a; 使用动态规划的思想&#xff0c;定义二维数组dp&#xff0c;其中dp[i][j]表示以nums[i]为结尾&#xff0c;公差为(j-1000)的等差数列长度。为了适应负数的情况&#xff0c;将公差的范围设为[-1000, 1000]&#xff0c;并且加上1000作为数组索引。 初始化r…

11:日志分析系统ELK|Elasticsearch|kibana

日志分析系统ELK&#xff5c;Elasticsearch&#xff5c;kibana 日志分析系统ELKELK概述Elasticsearch安装Elasticsearch部署Elasticsearch集群Elasticsearch插件 熟悉Elasticsearch的API调用_cat API创建 tedu 索引使用 PUT 方式增加数据查询数据修改数据删除数据 KibanaKibana…

锂电池SOC估计 | PyTorch实现基于Basisformer模型的锂电池SOC估计

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 PyTorch实现基于Basisformer模型的锂电池SOC估计 锂电池SOC估计&#xff0c;全新【Basisformer】时间序列预测 1.采用自适应监督自监督对比学习方法学习时序特征&#xff1b; 2.通过双向交叉注意力机制计算历史序列和…

BL、万科、中海地产、碧桂园、华润置地、佳兆业、金地商置、龙湖、绿城、融创、时代中国、旭辉、中国建筑校招笔试题

为了帮助应聘者更好地备战地产公司的招聘考试&#xff0c;我将介绍以下13套校招试题资料&#xff0c;涵盖了24 BL、24万科、24中海地产、碧桂园、华润置地、佳兆业、金地商置、龙湖、绿城、融创、时代中国、旭辉和中国建筑等知名房地产企业&#xff0c;为您提供全方位的备考资源…

提高移动应用的安全性:策略与实践

提高移动应用的安全性&#xff1a;策略与实践 随着移动应用的普及&#xff0c;安全性问题变得日益重要。用户数据保护、应用逻辑安全、以及防止恶意攻击都是开发者必须关注的重点。本文将探讨如何通过一系列策略和实践来提高移动应用的安全性。 1. 数据加密与保护 敏感数据加…

2024年环境安全科学、材料工程与制造国际学术会议(ESSMEM2024)

【EI检索】2024年环境安全科学、材料工程与制造国际学术会议&#xff08;ESSMEM2024) 会议简介 我们很高兴邀请您参加将在三亚举行的2024年环境安全科学、材料工程和制造国际学术会议&#xff08;ESSMEM 2024&#xff09;。 ESSMEM2024将汇集世界各国和地区的研究人员&…

初识Lombok

前言 最近读一些公司的业务代码&#xff0c;发现近几年的java项目工程中都使用了lombok&#xff0c;lombok是一个可以自动生成get,set、toString等模板类方法的工具框架&#xff0c;程序再引入lombok后&#xff0c;添加一个注解便可以不写get\set\toString等方法。 Lombok示例…

计算机组成原理(15)----输入/输出系统

目录 一.I/O系统的基本概念 &#xff08;1&#xff09;I/O硬件 &#xff08;2&#xff09;I/O控制方式 1.程序查询方式 2.程序中断方式 3.DMA&#xff08;Direct Memory Access&#xff09;控制方式 4.通道控制方式 &#xff08;3&#xff09;I/O软件 1.I/O指令 2.通…

全志H713/H618方案:调焦电机(相励磁法步进电机)的驱动原理、适配方法

一、篇头 全志H713平台&#xff0c;作为FHD投影的低成本入门方案&#xff0c;其公板上也配齐了许多投影使用的模组&#xff0c;本文即介绍投影仪调焦所用的步进电机&#xff0c;此模组的驱动原理、配制方法、调试方法。因为条件限制&#xff0c;本文采用的是H618香橙派Z3平台&…

Linux-进程-007

1进程 1.1进程基本概念 程序&#xff1a;存放在外存中的一段数据组成的文件 进程&#xff1a;是一个程序动态执行的过程&#xff0c;包括进程的创建&#xff0c;进程的调度&#xff0c;进程的消亡1.2进程相关命令 1.2.1打开任务管理器 【top】&#xff1a;动态查看当前系统…

国企招聘考试------笔试资料-校园招聘

国企招聘考试一直备受广大求职者的关注&#xff0c;因为国企招聘通常具有稳定的岗位、优厚的福利待遇和广阔的发展空间&#xff0c;因此备战国企招聘考试成为许多求职者的重要任务。为了帮助求职者更好地准备国企招聘笔试&#xff0c;我将为你介绍这套校招试题资料。 国企招聘…

idea集成git(实用篇)

0.Git常用命令 Git常用命令-CSDN博客 1.下载git Git - Downloads 一路傻瓜式安装即可&#xff08;NEXT&#xff09; 2.软件测试 在Windows桌面空白处&#xff0c;点击鼠标右键&#xff0c;弹出右键菜单 Git软件安装后&#xff0c;会在右键菜单中增加两个菜单 Git GUI He…

Go编译到linux运行出现 cannot execute binary file

1.初学Go就在windows上写了个"Hello,World!",在windown上编译了一下&#xff0c;生成了可执行文件。运行无问题 go build text.go .\text.exe Hello,World!2.但是按照网上的教程进行生成linux的可执行文件时出现报错 set CGO_ENABLED0 set GOOSlinux set GOARCHam…

程序媛的mac修炼手册-- 2024如何彻底卸载Python

啊&#xff0c;前段时间因为想尝试chatgpt的API&#xff0c;需要先创建一个python虚拟环境来安装OpenAI Python library. 结果&#xff0c;不出意外的出意外了&#xff0c;安装好OpenAI Python library后&#xff0c;因为身份认证问题&#xff0c;根本就没有获取API key的权限…