022——设计通信帧格式

本期没想好怎么排版以流水账形式展示了

int tcp_server(int argc, char *argv[]) 
{int server_fd, client_fd;  struct sockaddr_in server_addr, client_addr;  socklen_t client_len = sizeof(client_addr); char *ip_address = argv[1];  int port = atoi(argv[2]);  // 创建TCP套接字  if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {  perror("socket creation failed");  exit(EXIT_FAILURE);  }  // 设置服务器地址信息  memset(&server_addr, 0, sizeof(server_addr));  server_addr.sin_family = AF_INET;  server_addr.sin_addr.s_addr = inet_addr(ip_address);  server_addr.sin_port = htons(port);  // 绑定套接字到服务器地址  if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {  perror("bind failed");  exit(EXIT_FAILURE);  }  // 监听套接字  if (listen(server_fd, 5) < 0) {  perror("listen failed");  exit(EXIT_FAILURE);  }  printf("Server listening on %s:%d...\n", ip_address, port);  //处理僵尸进程signal(SIGCHLD, SIG_IGN);// 接受客户端连接  if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) < 0) {  perror("accept failed");goto err1;}while (1) {// 打印客户端信息  char client_ip[INET_ADDRSTRLEN];  inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);  printf("Client connected from %s:%d\n", client_ip, ntohs(client_addr.sin_port));  do_client(client_fd);}err2:close(client_fd);
err1:close(server_fd);return NOERROR;  
}

修改了一下服务器程序

int do_client(int acceptfd)
{MSG msg;char rx_buffer[BUFFER_SIZE];char tx_buffer[BUFFER_SIZE];// 接收客户端消息  memset(rx_buffer, 0, BUFFER_SIZE);memset(tx_buffer, 0, BUFFER_SIZE);ssize_t bytes_read = recv(client_fd, rx_buffer, BUFFER_SIZE - 1, 0);  if (bytes_read < 0) {  perror("recv failed");  goto err2;}// 确保消息以换行符结尾,并打印接收到的消息  // if (bytes_read > 0 && rx_buffer[bytes_read - 1] != '\n') {  //     rx_buffer[bytes_read] = '\n';  //     rx_buffer[bytes_read + 1] = '\0';  // }  printf("Received message: %s", rx_buffer);  // 回复客户端消息  //strcpy(tx_buffer, "Hello, client!\n");if (send(client_fd, tx_buffer, strlen(tx_buffer), 0) < 0) {  perror("send failed");  }return 0;
}

加了个结构体描述命令

编译咔咔报错

用信号报错要加这个

goto报错修改一下代码

if忘记括号了

局部变量名字用错了

msg定义了没用

因为借鉴了我以前写的ftp服务器所以双主函数报错了

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>#define   N  32#define  L  1   // user - list
#define  G  2   // user - get file
#define  P  3   // user - put file
#define  Q  4   // user - quit// 定义通信双方的信息结构体
typedef struct {int type;                        //命令char data[1024];                 //文件具体内容char filename[256][256];         //文件名int len;                     //文件数量int error;
}MSG;int do_get_time();
int do_client(int acceptfd, sqlite3 *db);
void do_list(int acceptfd, MSG *msg);
long back_size(const char *file);
void Download(int acceptfd, MSG *msg);
void put(int acceptfd, MSG *msg);
// ./server  192.168.3.196  10000
int main(int argc, const char *argv[])
{int sockfd;struct sockaddr_in  serveraddr;int n;MSG  msg;sqlite3 *db;int acceptfd;pid_t pid;if(argc != 3){printf("Usage:%s serverip  port.\n", argv[0]);return -1;}if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0){perror("fail to socket.\n");return -1;}bzero(&serveraddr, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){perror("fail to bind.\n");return -1;}// 将套接字设为监听模式if(listen(sockfd, 5) < 0){printf("fail to listen.\n");return -1;}//处理僵尸进程signal(SIGCHLD, SIG_IGN);while(1){if((acceptfd = accept(sockfd, NULL, NULL)) < 0){perror("fail to accept");return -1;}if((pid = fork()) < 0){perror("fail to fork");return -1;}else if(pid == 0)  // 儿子进程{//处理客户端具体的消息close(sockfd);do_client(acceptfd, db);}else  // 父亲进程,用来接受客户端的请求的{close(acceptfd);}}return 0;
}int do_client(int acceptfd, sqlite3 *db)
{MSG msg;while(recv(acceptfd, &msg, sizeof(msg), 0) > 0){printf("type:%d\n", msg.type);switch(msg.type){case L:do_list(acceptfd, &msg);break;case G:Download(acceptfd, &msg);break;case P:put(acceptfd, &msg);break;case Q://do_history(acceptfd, &msg, db);//TODObreak;default:printf("Invalid data msg.\n");}}printf("client exit.\n");close(acceptfd);exit(0);return 0;
}void do_list(int acceptfd, MSG *msg)
{DIR *d; //声明一个句柄struct dirent *file; //readdir函数的返回值就存放在这个结构体中struct stat sb;msg->len = 0;if(!(d = opendir("./"))){printf("error opendir %s!!!\n","./");exit(1);}while((file = readdir(d)) != NULL){//把当前目录.,上一级目录..及隐藏文件都去掉,避免死循环遍历目录if(strncmp(file->d_name, ".", 1) == 0)continue;strcpy(msg->filename[msg->len++], file->d_name); //保存遍历到的文件名}closedir(d);if(send(acceptfd, msg, sizeof(MSG), 0) < 0){perror("fail to send");return ;}printf("目录清单已经成功发送\n");
}void Download(int acceptfd, MSG *msg)
{FILE* fd = NULL;size_t num_read;fd = fopen(msg->filename[0], "r"); // 打开文件if(fd == NULL){perror("fopen");msg->error = 1;if(send(acceptfd, msg, sizeof(MSG), 0) < 0){perror("fail to send");return ;}return;}msg->len = back_size(msg->filename[0]);num_read = fread(msg->data, 1, msg->len, fd); // 读文件内容printf("file is %d bit\n",msg->len);if (num_read < 0){ printf("error in fread()\n");fclose(fd);return ;}msg->error = 0;if(send(acceptfd, msg, sizeof(MSG), 0) < 0){perror("fail to send");fclose(fd);return ;}printf("%s已经成功发送\n",msg->filename[0]);fclose(fd);
}void put(int acceptfd, MSG *msg)
{size_t num_write;FILE* fd = NULL;if(msg->error == 0){fd = fopen(msg->filename[0], "w"); // 打开文件if(fd == NULL){perror("fopen");return ;}num_write = fwrite(msg->data, 1, msg->len, fd); //写文件内容if (num_write < 0){ printf("error in fwrite()\n");fclose(fd);return ;}printf("%s创建并写入完成\n",msg->filename[0]);fclose(fd);return ;}else{printf(" server error\n");return ;	}	
}long back_size(const char *file)
{//打开需要计算大小的文件FILE *frp = fopen(file,"r");if(NULL == frp){perror("fopen");exit(EXIT_FAILURE);}//将文件指针置于文件末尾fseek(frp,0,SEEK_END);//计算文件大小并返回return ftell(frp);
}

好了这下没问题了

有毛病啊

while(1)的问题应该放到do_client做的

int do_client(int acceptfd)
{//MSG msg;char rx_buffer[BUFFER_SIZE];char tx_buffer[BUFFER_SIZE];while(1){// 接收客户端消息  memset(rx_buffer, 0, BUFFER_SIZE);memset(tx_buffer, 0, BUFFER_SIZE);ssize_t bytes_read = recv(acceptfd, rx_buffer, BUFFER_SIZE - 1, 0);  if (bytes_read < 0) {  perror("recv failed");  return ERROR;}// 确保消息以换行符结尾,并打印接收到的消息  // if (bytes_read > 0 && rx_buffer[bytes_read - 1] != '\n') {  //     rx_buffer[bytes_read] = '\n';  //     rx_buffer[bytes_read + 1] = '\0';  // }  printf("Received message: %s", rx_buffer);  // 回复客户端消息  //strcpy(tx_buffer, "Hello, client!\n");if (send(acceptfd, tx_buffer, strlen(tx_buffer), 0) < 0) {  perror("send failed");  }}return NOERROR;
}

新问题

改一下让他收到什么返回什么

经典缓冲区问题

退出也有问题

还缺一个快速重新绑定

这里也有问题

sendall只能发送字节序不能发送字符串

所以要这样处理一下

int do_client(int acceptfd)
{//MSG msg;char rx_buffer[BUFFER_SIZE];char tx_buffer[BUFFER_SIZE];while(1){// 接收客户端消息  memset(rx_buffer, 0, BUFFER_SIZE);memset(tx_buffer, 0, BUFFER_SIZE);ssize_t bytes_read = recv(acceptfd, rx_buffer, BUFFER_SIZE - 1, 0);  if (bytes_read < 0) {  perror("recv failed");  return ERROR;}else{/*确保消息以换行符结尾,并打印接收到的消息*/  if (bytes_read > 0 && rx_buffer[bytes_read - 1] != '\n') {  rx_buffer[bytes_read] = '\n';  rx_buffer[bytes_read + 1] = '\0';  }if ('Q' == rx_buffer[0]){printf("client quit....\n");return ERROR;}printf("Received message: %s", rx_buffer);  // 回复客户端消息  //strcpy(tx_buffer, "Hello, client!\n");if (send(acceptfd, rx_buffer, strlen(rx_buffer), 0) < 0) {  perror("send failed");  }}}return NOERROR;
}

        但是这样改完有个问题消息内容是Q也会导致这面退出,我在想要留这个后门呢还是直接在python这面处理一下不允许直接发送Q。

        还是不允许发送好了,这个连接其实是程序自动的不是用户可输入的。加不加问题其实都不会存在。

现在就很完美了

最终版

#include "tcp.h"
#include "net.h"
#include "global.h"
/*
*author : xintianyu
*return : err num
*data   : 2024-4-10
-----------------------
*author : ???
*return : ???
*data   : ???
*/
int usage(int argc, char *argv[])
{ if (argc != 3){  printf("Usage: %s <ip_address> <port>\n", argv[0]);  return ERROR;  }else{return NOERROR;}
}void do_nothing()
{/*void*/
}/*
*author : xintianyu
*return : err num
*data   : 2024-4-10
-----------------------
*author : ???
*return : ???
*data   : ???
*/
int tcp_server(int argc, char *argv[]) 
{int server_fd, client_fd;  struct sockaddr_in server_addr, client_addr;  socklen_t client_len = sizeof(client_addr); char *ip_address = argv[1];  int port = atoi(argv[2]);  // 创建TCP套接字  if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {  perror("socket creation failed");  exit(EXIT_FAILURE);  }  /*支持快速重新绑定*/int b_reuse = 1;setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));// 设置服务器地址信息  memset(&server_addr, 0, sizeof(server_addr));  server_addr.sin_family = AF_INET;  server_addr.sin_addr.s_addr = inet_addr(ip_address);  server_addr.sin_port = htons(port);  // 绑定套接字到服务器地址  if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {  perror("bind failed");  exit(EXIT_FAILURE);  }  // 监听套接字  if (listen(server_fd, 5) < 0) {  perror("listen failed");  exit(EXIT_FAILURE);  }  printf("Server listening on %s:%d...\n", ip_address, port);  //处理僵尸进程signal(SIGCHLD, SIG_IGN);// 接受客户端连接  if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) < 0) {  perror("accept failed");goto err1;}// 打印客户端信息  char client_ip[INET_ADDRSTRLEN];  inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);  printf("Client connected from %s:%d\n", client_ip, ntohs(client_addr.sin_port));if (ERROR == do_client(client_fd)){perror("client disconnect.....");goto err2;}err2:close(client_fd);
err1:close(server_fd);return NOERROR;  
}int do_client(int acceptfd)
{//MSG msg;char rx_buffer[BUFFER_SIZE];char tx_buffer[BUFFER_SIZE];int cmd;// 接收客户端消息memset(rx_buffer, 0, BUFFER_SIZE);memset(tx_buffer, 0, BUFFER_SIZE);while(1){ssize_t bytes_read = recv(acceptfd, rx_buffer, BUFFER_SIZE - 1, 0);  if (bytes_read < 0) {  perror("recv failed");  return ERROR;}else{/*确保消息以换行符结尾,并打印接收到的消息*/  if (bytes_read > 0 && rx_buffer[bytes_read - 1] != '\n') {  rx_buffer[bytes_read] = '\n';  rx_buffer[bytes_read + 1] = '\0';  }if ('Q' == rx_buffer[0]){printf("client quit....\n");return ERROR;}else{cmd = select_driver(rx_buffer);}printf("cmd is %d\n", cmd);
#if (STD_ON == DEBUG)printf("Received message: %s", rx_buffer);  // 回复客户端消息  //strcpy(tx_buffer, "Hello, client!\n");if (send(acceptfd, rx_buffer, strlen(rx_buffer), 0) < 0) {  perror("send failed");  }
#endif/*STD_ON == DEBUG*/}}return NOERROR;
}int select_driver(char * cmd)
{int opt = 0;if('@' == cmd[0]){
#if (STD_ON == DEBUG)printf("cmd[0] = @\n");
#endif/*STD_ON == DEBUG*/}else{printf("cmd[0] ERROR!!!\n");opt = ERROR;}opt = atoi(&cmd[1]);return opt;
}
import socket  server_ip   = '192.168.5.110'
server_port = 8888 # 设置服务器地址和端口  
server_address = (server_ip, server_port)# 创建一个socket对象  
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 连接到服务器  
try:  client_socket.connect(server_address)  print(f'Connected to {server_address}')  # 接收用户输入并发送给服务器  while True:  try:  user_input = input('Enter command (or "exit" to quit): ')  if user_input.lower() == 'exit':cmd = 'Q'client_socket.sendall(cmd.encode())breakwhile 'Q' == user_input:print(f'please input other string')user_input = input('Enter command (or "exit" to quit): ')client_socket.sendall(user_input.encode())  # 接收服务器的响应data = client_socket.recv(512)  print(f'Received: {data.decode()}')  except KeyboardInterrupt:  print('\nKeyboardInterrupt received, exiting...')  break  except ConnectionResetError:  print('\nConnection reset by server, exiting...')  break  except Exception as e:  print(f'An error occurred: {e}, trying to reconnect...')  client_socket.close()  # Close the socket if there's an error  client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # Create a new one  client_socket.connect(server_address)  # Reconnect to the server  finally:  # 关闭连接  print('Closing socket')  client_socket.close()

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

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

相关文章

Capture One 23 Enterprise for Mac中文版 全面的图像处理工具

Capture One 23 Enterprise for Mac中文版一款专业的图像编辑和管理软件&#xff0c;具备强大的功能和工具&#xff0c;适用于摄影师、摄影工作室和专业用户。 软件下载&#xff1a;Capture One 23 Enterprise for Mac中文版下载 该软件为用户提供了全面的图像处理工具&#xf…

SpringCloudAlibaba-整合nacos(二)

目录地址&#xff1a; SpringCloudAlibaba整合-CSDN博客 一、nacos服务部分 1.下载nacos&#xff0c;并执行数据库脚本&#xff1a;nacos-mysql.sql 2.修改配置文件&#xff0c;配置mysql 3.启动nacos ./startup.sh -m standalone 4.访问&#xff1a;http://127.0.0.1:884…

Terraform 扩展

Terraform 扩展 Terraform Meta-Arguments 元参数 count 创建相似的资源for_each 创建相似的资源depends_on 定义资源或者模块的依赖provider 定义provider选项lifecycle 资源的生命周期行为 参数使用范围备注countresource module适用于创建多个相似的资源&#xff0c;使用…

1999-2022年各省研究与试验发展人员全时当量数据/省研发人员全时当量数据/(RD)人员全时当量(无缺失)

1999-2022年各省研究与试验发展人员全时当量数据/省研发人员全时当量数据/(R&D)人员全时当量&#xff08;无缺失&#xff09; 1、时间&#xff1a;1999-2022年 2、来源&#xff1a;科技年鉴 3、指标&#xff1a;研究与试验发展人员全时当量/研发人员全时当量 4、范围&a…

软考-系统集成项目管理中级-新一代信息技术

本章历年考题分值统计 本章重点常考知识点汇总清单(掌握部分可直接理解记忆) 本章历年考题及答案解析 32、2019 年上半年第 23 题 云计算通过网络提供可动态伸缩的廉价计算能力&#xff0c;(23)不属于云计算的特点。 A.虚拟化 B.高可扩展性 C.按需服务 D.优化本地存储 【参考…

Docker快速上手及常用命令速查

Docker快速上手 安装 在ubuntu上安装docker: sudo apt-get install docker docker -v #查看版本在centos7上安装docker&#xff1a;(docker在YUM源的Extras仓库中) yum install docker systemctl start dockerdocker常用命令速查 #查看docker信息 docker info #查看本地镜…

hive 数据库表常用操作及相关函数讲解

创建数据库并指定hdfs存储位置 create database myhive2 location ‘/myhive2’; 使用location关键字&#xff0c;可以指定数据库在HDFS的存储路径。 Hive的库在HDFS上就是一个以.db结尾的目录 默认存储在&#xff1a; /user/hive/warehouse内 当你为Hive表指定一个LOCATION时…

NumPy入门(一)

NumPy入门(一) 工具: jupyter notebook jupyter notebook 功能 : 数据处理 &#xff08;python 处理数据功能&#xff09; coding文字型的描述 富文本 word可视化支持 官网: https://jupyter.org/ 启动命令 jupyter notebook 1.1 numpy简介 Python的拓展库, 提供数据对象 nda…

【数据下载】SODA数据更新至2022并教学下载

【数据下载】SODA数据更新至2022并教学下载 我为什么那么喜欢使用SODA数据&#xff1f; 就是三维网格化的数据&#xff0c;好用。 但是需要高分辨率还是需要找别的。 以前分享过SODA数据下载&#xff0c;但上次版本过于凌乱。因此重新借助更新再分享一次&#xff0c;不为过。…

人脸识别业务(基于腾讯人脸识别接口)

使用腾讯云人脸识别接口&#xff0c;基于优图祖母模型。 一、准备工作 人脸识别账号 申请腾讯云服务器账号&#xff0c;生成自己的秘钥。记录秘钥和秘钥ID。 创建人员库 记下人员库id 在配置文件application.yml中添加配置。 plateocr:SecretId: 秘钥IDSecretKey: 秘钥ser…

Day1 省选衔接题 思路总结

Day1 省选题 思路 取数 可反悔的贪心。我们开一个双向链表记录此时每个数的前/后一个数是什么。一个简单但不一定正确的贪心策略即为&#xff1a;每次都取走当前值最大的且可取的数&#xff0c;并更新列表。考虑如何使这个贪心思路正确。 设 p r e x pre_x prex​ 表示 x x …

Path Aggregation Network for Instance Segmentation

PANet 摘要1. 引言2.相关工作3.框架 PANet 最初是为 proposal-based 实例分割框架提出来的&#xff0c;mask 是实例的掩码&#xff0c;覆盖了物体包含的所有像素&#xff0c;proposal 在目标检测领域是可能存在目标的区域。在实例分割中&#xff0c;首先利用RPN(Region Proposa…

练习题(2024/4/10)

1. 删除有序数组中的重复项 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元…

2022年蓝桥杯省赛——直线

目录 题目链接&#xff1a;11.直线 - 蓝桥云课 (lanqiao.cn) 题目描述 思路 代码思路如下 代码实现 坑来喽~~ 导致这个BUG的原因&#xff01;&#xff01;&#xff01; 总结 整体的 两种b的情况对比数据 题目链接&#xff1a;11.直线 - 蓝桥云课 (lanqiao.cn) 题目描…

JVM面试整理--对象的创建和堆

文章目录 对象的创建过程是怎样的?对象在内存中的结构是怎样的&#xff08;专业的叫法&#xff1a;对象的内存布局&#xff09;对象在内存分配时使用的哪种方式&#xff08;有的地方也称为&#xff1a;分配算法&#xff09;知道什么是“指针碰撞”吗&#xff1f;知道什么是“空…

LeetCode 80—— 删除有序数组中的重复项 II

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 让 index指向删除重复元素后数组的新长度&#xff1b;让 st_idx 指向重复元素的起始位置&#xff0c;而 i 指向重复元素的结束位置&#xff0c;duplicate_num代表重复元素的个数&#xff1b;一段重复元素结束后&am…

php校园活动报名系统vue+mysql

开发语言&#xff1a;php 后端框架&#xff1a;Thinkphp/Laravel 前端框架&#xff1a;vue.js 服务器&#xff1a;apache 数据库&#xff1a;mysql 运行环境:phpstudy/wamp/xammp等本选题则旨在通过标签分类管理等方式&#xff0c;管理员&#xff1b;首页、个人中心、学生管理、…

Redis 缓存穿透、缓存击穿、缓存雪崩区别和解决方案

缓存穿透 什么是缓存穿透&#xff1f; 缓存穿透说简单点就是大量请求的 key 是不合理的&#xff0c;根本不存在于缓存中&#xff0c;也不存在于数据库中 。这就导致这些请求直接到了数据库上&#xff0c;根本没有经过缓存这一层&#xff0c;对数据库造成了巨大的压力&#xf…

2、Qt UI控件 -- qucsdk项目使用

前言&#xff1a;上一篇文章讲了qucsdk的环境部署&#xff0c;可以在QDesigner和Qt Creator中看到qucsdk控件&#xff0c;这一篇来讲下在项目中使用qucsdk库中的控件。 一、准备材料 要想使用第三方库&#xff0c;需要三个先决条件&#xff0c; 1、控件的头文件 2、动/静态链…