【面试题总结1】-Static、Const、QT中基于TCP的通信服务器/客户端操作

1、在C++和C中static关键字的用法

在C语言和C++中,

① static修饰未初始化全局变量结果默认为0

② 当static修饰局部变量时,只是延长了这个变量的生命周期,并没有改变其作用域

     比如说,这个变量是在哪个函数被定义的,那么它的作用域就只在这个函数中,但是它的声明周期被延长了,一般的局部变量时函数结束,变量就会被释放掉,但是以static修饰的局部变量,会在整个项目结束时才被释放,所以它的值能够被保留,再次调用该函数时,不会重新被定义出来,是继续使用之前的这一个变量;

③ 用static修饰的函数只能在本文件中被调用不能被跨文件调用

④ 用static修饰的全局变量不能用extern引用到其他文件使用

⑤ 用static修饰的指针不能指向auto类型的地址。因为计算机时先为静态变量分配空间,再分配auto类型的变量,不可以使用指针指向不存在的变量地址。

在C++中,有静态数据成员静态成员函数两个概念,

静态数据成员静态成员函数都属于类但不属于类的实例化,它们所有类的实例当中,是共享的。

静态数据成员就是在类中定义数据时,在数据成员前+static关键字,它需要在类外进行初始化,如果不初始化的话默认结果为0,但不建议这么做。

静态成员函数也就是在类中定义函数时在函数声明前+static静态成员函数 只能访问 静态数据成员

2、在C++和C中const关键字的用法

const的作用是:保护数据不被修改

  1. 当const修饰一个普通变量时,说明这个变量的值不能被修改,所以在定义该普通变量时要对其初始化否则后期无法更改它的值
  2. const修饰的全局变量,(值不能被修改),变量的空间在静态区的只读段
  3. const修饰的局部变量,(值不能被修改),变量的空间在栈区
  4. 将const放在*号前面,修饰的是,如果放在*后面,表示指针的指向不能修改,可以通过指针修改指针中的值,如果两个都修饰(*前后都有const),两个都不能更改
  5. const修饰函数形参数据,则为保护形参数据不被更改。当指针引用作为函数形参,不能该值的时候需要用const修饰
  6. const修饰函数的返回值,(修饰指针、引用作为形参,保护形参数据不被更改)如果修饰的是值返回,可修饰,可不修饰,当修饰的是指针或者引用返回的时候,需要设置成const

在C++中,const修饰的成员变量,代表这是常成员变量,必须使用初始化列表进行初始化。
① 当类中有常成员的时候,必须使用初始化列表进行初始化,
② 类中有成员子对象时,调用构造函数完成初始化列表
③ 保护成员变量不被修改
④ 任意一个常成员函数中不能修改常成员变量的值,除非使用mutable关键字(取消常属性)

3、详细说一下QT中基于TCP的通信中服务器端操作
  1. 创建一个QTCPServer的类对象,该类对象就是一个服务器
  2. 将该对象调用listen函数设置成监听状态,监听时,可以监听指定的ip地址,也可以监听所有主机地址(Any),可以通过指定端口号,也可让该服务器自动选择
  3. 当有客户端发来连接请求时,该服务器就会自动发射一个newConnection的信号,我们可以将该信号连接到自定义的槽函数中处理相关逻辑
  4.  在槽函数中,可以调用nextPendingConnetion函数可以获取最新连接的客户端套接字的地址,我们可以将该套接字存入到客户端容器中
  5. 此时,服务器已经和客户端建立连接请求了,如果有客户端向服务器发来数据,那么对于的客户端套接字就会发射一个readyRead的信号
  6. 读取套接字中的数据使用read、readLine、readAll函数来完成
  7. 向套接字中数据,可以使用write函数完成
  8. 关闭服务器,使用close来完成
  • 注意:QByteArray和QString之间的转换
4、详细说一下QT中基于TCP的通信中客户端操作
  1. 实例化一个QTCPSocket的类对象
  2. 调用该对象的成员函数connectToHost连接到服务,连接服务器时,需要给定服务器的ip地址和端口号
  3. 如果连接服务器成功,那么该客户端就会自动发射一个connected的信号,我们可以将该信号连接到槽函数中处理相关逻辑
  4. 如果服务器有数据向客户端发来,那么该客户端就会自动发射一个readyRead信号,我们可以在该信号对应的槽函数中处理数据
  5. 可以使用read、readLine、readAll读取客户端套接字中的数据
  6. 可以使用write向服务器发送数据
  7. 使用成员函数disConnectFromHost断开与服务器的连接
  8. 如果成功断开与服务器的连接,那么该套接字就会自动发射一个disconnected的信号
  • 注意:QByteArray和QString之间的转换

    各个信号在构造函数内连接即可,不用在槽函数中连接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
西北师范大学计算机科学与工程学院 学生实验报告 学号 日期 : "系别 "计算机科学 "专业 " "班级 " "姓 名 " " " "与工程学院 " " " " " " " "课程 " "课程 " "学时数 "2 " "名称 " "类型 " " " " "实验 "实验二、基于TCP服务器/客户端编程 " "名称 " " "实验目的:1、掌握Linux下的TCP客户端基本原理和基本编程方法 " " " "实验内容: " "1、写Linux下TCP服务器套接字程序,程序运行时服务器等待客户的连接,一旦连接 " "成功,则显示客户的IP地址、端口号,并向客户端发送字符串。 " "2、写Linux下TCP客户端套接字程序,结合TCP服务器端程序,实现以下功能: " "(1)、客户根据用户提供的IP地址连接到相应的服务器; " "(2)、服务器等待客户的连接,一旦连接成功,则显示客户的IP地址、端口号,并 " "向客户端发送字符串; " "(3)、客户接收服务器发送的信息并显示。 " "实验步骤: " "TCP服务端程序设计 " "使用TCP套接字编程可以实现基于TCP/IP协议的面向连接的通信,它分为服务器端和 " "客户端两部分,其主要实现过程如图所示。 " " " " " " 图1.1 TCP客户/服务器的套接字函数 " " " "socket函数:为了执行网络输入输出,一个进程必须做的第一件事就是调用socket函" "数获得一个文件描述符。 " " #include <sys/socket.h> " " int socket(int family,int type,int protocol);     " "     返回:非负描述字---成功   -1---失败 " "  第一个参数指明了协议簇,目前支持5种协议簇,最常用的有AF_INET(IPv4协议)" "和AF_INET6(IPv6协议);第二个参数指明套接口类型,有三种类型可选:SOCK_STREA" "M(字节流套接口)、SOCK_DGRAM(数据报套接口)和SOCK_RAW(原始套接口);如果套接 " "口类型不是原始套接口,那么第三个参数就为0。 " "2、connect函数:当用socket建立了套接口后,可以调用connect为这个套接字指明" "远程端的地址;如果是字节流套接口,connect就使用三次握手建立一个连接;如果 " "是数据报套接口,connect仅指明远程端地址,而不向它发送任何数据。 " "#include <sys/socket.h>       " " int connect(int sockfd, const struct sockaddr * addr, socklen_t " "addrlen);   " "           返回:0---成功   -1---失败 " "  第一个参数是socket函数返回的套接口描述字;第二和第三个参数分别是一个指" "向套接口地址结构的指针和该结构的大小。 " "这些地址结构的名字均已"sockaddr_"开头,并以对应每个协议族的唯一后缀结束。 " "以IPv4套接口地址结构为例,它以"sockaddr_in"命名,定义在头文件<netinet/in.h" ">;以下是结构体的内容: " "struct in_addr " "{ " " in_addr_t s_addr;     " "}; " "struct sockaddr_in { " " uint8_t sin_len; " " sa_family_t sin_family; " " in_port_t sin_port; " " struct in_addr sin_addr; " " char sin_zero[8]; " "}; " "bind函数:为套接口分配一个本地IP和协议端口,对于网际协议,协议地址是32位IP" "v4地址或128位IPv6地址与16位的TCP或UDP端口号的组合;如指定端口为0,调用bind" "时内核将选择一个临时端口,如果指定一个通配IP地址,则要等到建立连接后内核才" "选择一个本地IP地址。 " "#include <sys/socket.h>   " " int bind(int sockfd, const struct sockaddr * server, socklen_t addrlen); " " 返回:0---成功   -1---失败  " " " "  第一个参数是socket函数返回的套接口描述字;第二和第第三个参数分别是一个" "指向特定于协议的地址结构的指针和该地址结构的长度。 " "listen函数:listen函数仅被TCP服务器调用,它的作用是将用soc
实现C/C++TCP服务器/客户端多人聊天室,需要以下步骤: 1. 确定通信协议 在TCP/IP协议服务器客户端之间的通信使用套接字(Socket)实现。服务器客户端之间的通信协议需要在客户端服务器之间进行协商,确定信息的格式和传输方式。 2. 设计服务器程序 服务器需要具有以下功能: - 监听客户端的连接请求。 - 接收客户端发送的信息,并将信息转发给其他客户端。 - 维护客户端连接状态,包括处理连接请求、处理断开连接请求等。 3. 设计客户端程序 客户端需要具有以下功能: - 连接服务器。 - 发送消息给服务器。 - 接收服务器转发的其他客户端发送的消息。 - 登录验证。 4. 实现用户账号密码用txt保存并读取 可以使用文件读写API实现用户账号密码用txt保存并读取。具体实现可以在服务器端或客户端实现。 下面是一个简单的C++代码实现多人聊天室的服务器客户端服务器端代码: ```c++ #include <iostream> #include <string> #include <cstring> #include <cstdio> #include <cstdlib> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <pthread.h> #include <map> #define MAX_CLIENT_NUM 100 #define BUFF_SIZE 1024 using namespace std; struct ClientInfo { int sock_fd; string username; }; map<int, ClientInfo> client_list; // 客户端列表 pthread_mutex_t mutex_client_list; // 客户端列表的锁 void send_message(const char* message, int sender_sock_fd) { pthread_mutex_lock(&mutex_client_list); for (auto& client : client_list) { if (client.second.sock_fd != sender_sock_fd) { write(client.second.sock_fd, message, strlen(message)); } } pthread_mutex_unlock(&mutex_client_list); } void* handle_client(void* arg) { int sock_fd = *(int*)arg; char buff[BUFF_SIZE] = {0}; string username; // 接收客户端的用户名 read(sock_fd, buff, BUFF_SIZE); username = buff; pthread_mutex_lock(&mutex_client_list); ClientInfo client_info; client_info.sock_fd = sock_fd; client_info.username = username; client_list.insert(make_pair(sock_fd, client_info)); pthread_mutex_unlock(&mutex_client_list); printf("User %s connected.\n", username.c_str()); // 广播有新用户连接 string message = username + " joined the room.\n"; send_message(message.c_str(), sock_fd); // 循环处理客户端消息 while (true) { memset(buff, 0, sizeof(buff)); int recv_len = read(sock_fd, buff, BUFF_SIZE); if (recv_len <= 0) { // 客户端断开连接 pthread_mutex_lock(&mutex_client_list); client_list.erase(sock_fd); pthread_mutex_unlock(&mutex_client_list); printf("User %s disconnected.\n", username.c_str()); // 广播有用户断开连接 string message = username + " left the room.\n"; send_message(message.c_str(), sock_fd); close(sock_fd); break; } // 广播客户端发送的消息 message = username + ": " + buff; send_message(message.c_str(), sock_fd); } return NULL; } int main(int argc, char* argv[]) { if (argc != 2) { printf("Usage: %s <port>\n", argv[0]); exit(-1); } int server_sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_sock_fd < 0) { perror("socket"); exit(-1); } int port = atoi(argv[1]); sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = INADDR_ANY; if (bind(server_sock_fd, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("bind"); exit(-1); } if (listen(server_sock_fd, MAX_CLIENT_NUM) < 0) { perror("listen"); exit(-1); } pthread_mutex_init(&mutex_client_list, NULL); while (true) { sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int client_sock_fd = accept(server_sock_fd, (sockaddr*)&client_addr, &client_addr_len); if (client_sock_fd < 0) { perror("accept"); continue; } pthread_t thread_id; pthread_create(&thread_id, NULL, handle_client, &client_sock_fd); pthread_detach(thread_id); } return 0; } ``` 客户端代码: ```c++ #include <iostream> #include <string> #include <cstring> #include <cstdio> #include <cstdlib> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #define BUFF_SIZE 1024 using namespace std; int main(int argc, char* argv[]) { if (argc != 3) { printf("Usage: %s <ip> <port>\n", argv[0]); exit(-1); } int sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (sock_fd < 0) { perror("socket"); exit(-1); } int port = atoi(argv[2]); sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); if (inet_pton(AF_INET, argv[1], &server_addr.sin_addr) < 0) { perror("inet_pton"); exit(-1); } if (connect(sock_fd, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("connect"); exit(-1); } char buff[BUFF_SIZE] = {0}; string username, password; // 登录验证 printf("Please enter your username: "); cin >> username; printf("Please enter your password: "); cin >> password; sprintf(buff, "%s:%s", username.c_str(), password.c_str()); write(sock_fd, buff, strlen(buff)); // 循环处理用户输入和服务器消息 while (true) { fd_set read_set; FD_ZERO(&read_set); FD_SET(STDIN_FILENO, &read_set); FD_SET(sock_fd, &read_set); select(sock_fd + 1, &read_set, NULL, NULL, NULL); if (FD_ISSET(STDIN_FILENO, &read_set)) { // 从标准输入读取用户输入,发送给服务器 string message; getline(cin, message); sprintf(buff, "%s", message.c_str()); write(sock_fd, buff, strlen(buff)); } if (FD_ISSET(sock_fd, &read_set)) { // 从服务器读取消息,输出到标准输出 memset(buff, 0, sizeof(buff)); int recv_len = read(sock_fd, buff, BUFF_SIZE); if (recv_len <= 0) { printf("Disconnected from server.\n"); break; } printf("%s", buff); } } close(sock_fd); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值