TCP服务器与客户端搭建

一、思维导图

二、给代码添加链表

        【server.c】

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;enum Type{TYPE_REGIST,TYPE_LOGIN
};typedef struct Pack{int size;enum Type type;char buf[2048];int count;
}pack_t;/*
typedef struct user_info{union Data{struct user_info* tail;char ui[20];}data;struct user_info* next;struct user_info* prev;
}UserInfo;UserInfo* create_node(){UserInfo* node = malloc(sizeof(UserInfo));node->next = NULL;node->prev = NULL;node->data.tail = node;return node;
}
*///从pack协议包中解析数据
void read_pack(pack_t* pack)
{char* buf = pack->buf;//记录buf已经读取的字节个数,方便定位到最靠前的未读取的位置int readed_size = 0;while(1){//将buf中最靠前未读取的2个字节,当作short读取,并赋值给data_sizeshort data_size = *(short*)(buf + readed_size);if(data_size == 0){printf("数据解析完毕\n");break;}//因为已经读取了2个字节,readed_size要自增2字节readed_size += 2;//准备一个大小为data_size+1的字符数组,用来接收数据char temp[data_size + 1];//初始化该数组memset(temp, 0, data_size+1);memcpy(temp, buf + readed_size, data_size);readed_size += data_size;printf("temp = %s\n", temp);}
}int main(int argc, const char* argv[])
{if(argc != 2){printf("请输入端口号!\n");return 1;}//将字符串转换成int类型portint port = atoi(argv[1]);//创建服务器套接字int server = socket(AF_INET, SOCK_STREAM, 0);//准备网络地址结构体: struct sockaddr_inaddr_in_t addr = {0};addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr("0.0.0.0");//为套接字绑定ip和portif(bind(server, (addr_t*)&addr, sizeof(addr)) == -1){perror("bind()");return 1;}//监听listen(server, 10);//接收客户端的连接addr_in_t client_addr = {0};int client_addr_len = sizeof(client_addr);int client = accept(server, (addr_t*)&client_addr, &client_addr_len);if(client != -1){printf("=== 客户端连接 ===\n");}//读取客户端发来的消息while(1){int pack_size = 0;int res = read(client, &pack_size, 4);if(res == 0){printf("=== 客户端断开连接 === \n");return 0;}//当前的 pack_size = 4(pack.size大小) + 4(pack.type大小) + buf大小pack_t pack = {0};read(client, (char*)&pack+4, pack_size-4);pack.size = pack_size;//解析协议包的所有数据read_pack(&pack);}return 0;
}

        【client.c】

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;enum Type{TYPE_REGIST,TYPE_LOGIN
};typedef struct Pack{int size; //记录整个协议包实际大小(定长部分,占4个字节)enum Type type; //定长部分,占4个字节char buf[2048]; //变长部分,占count个字节int count; //记录指针偏移量,即buf使用了多少个字节
}pack_t;/*
typedef struct user_info{union Data{struct user_info* tail;char ui[20];}data;struct user_info* next;struct user_info* prev;
}UserInfo;UserInfo* create_node(){UserInfo* node = malloc(sizeof(UserInfo));node->next = NULL;node->prev = NULL;node->data.tail = node;return node;
}
*/void append(pack_t* pack, const char* data)
{char* buf = pack->buf;int len = strlen(data);//将buf的前2个字节当作short来存储数据len*(short*)(buf + pack->count) = len;pack->count += 2;memcpy(buf + pack->count, data, len);pack->count += len;pack->size = pack->count + 8;
}int main(int argc, const char* argv[])
{if(argc != 2){printf("请输入端口号!\n");return 1;}//将字符串转换成int类型portint port = atoi(argv[1]);int client = socket(AF_INET, SOCK_STREAM, 0);addr_in_t addr = {0};addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr("192.168.126.155");if(connect(client, (addr_t*)&addr, sizeof(addr)) == -1){perror("connect()");return 1;}while(1){pack_t pack = {0};pack.type=TYPE_LOGIN;char name[20] = "";char pwd[20] = "";printf("请输入账号:");scanf("%20s", name);while(getchar() != 10);printf("请输入密码:");scanf("%20s", pwd);while(getchar() != 10);//前2个字节记录数据长度n,紧接着的n个字节记录数据本身//将name和pwd存入pack.buf中(即将name和pwd按照既定格式添加进协议包))append(&pack, name);append(&pack, pwd);//协议包总共占据 pack.count + 4 字节//pack.count 的长度,根据name和pwd的长度动态决定write(client, &pack, pack.size);}return 0;
}

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

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

相关文章

【自动化测试】使用Python selenium类库模拟手人工操作网页

使用Python selenium类库模拟手人工操作网页 背景准备工作安装Python版本安装selenium类库下载selenium驱动配置本地环境变量 自动化脚本输出页面表单自动化填充相关代码 背景 待操作网页必须使用IE浏览器登录访问用户本地只有edge浏览器&#xff0c;通过edge浏览器IE模式访问…

如何通过Davinci Configurator来新增一个BswM仲裁规则

本文框架 前言1.增加一个Mode Declaration Group2.增加一个Mode Request RPorts3.与操作Port的SWC连线4.新建一个Expression5.新建ActionList6.将表达式新建或加进现有Rule内7.生成BswM及Rte模块代码8.在代码中调用RTE接口前言 在Autosar模式管理系列介绍01-BswM文章中,我们对…

智慧交通:如何通过数据可视化提升城市交通效率

随着城市化进程的加速&#xff0c;交通管理面临着前所未有的挑战。为了应对日益复杂的交通状况&#xff0c;智慧交通系统应运而生&#xff0c;其中数据可视化技术成为了提升交通管理效率的关键一环。本文将探讨如何利用山海鲸可视化软件来优化交通管理&#xff0c;并展示其在智…

Android Studio:如何利用Application操作全局变量

目录 一、全局变量是什么 二、如何把输入的信息存储到全局变量 2.1 MainApplication类 2.2 XML文件 三、全局变量读取 四、修改manifest ​编辑 五、效果展示 一、全局变量是什么 全局变量是指在程序的整个生命周期内都可访问的变量&#xff0c;它的作用范围不限于某个…

Kafka 可靠性探究—副本刨析

Kafka 的多副本机制提升了数据容灾能力。 副本通常分为数据副本与服务副本。数据副本是指在不同的节点上持久化同一份数据&#xff1b;服务副本指多个节点提供同样的服务&#xff0c;每个节点都有能力接收来自外部的请求并进行相应的处理。 1 副本刨析 1.1 相关概念 AR&…

Unity Dots学习

ISystem和SystemBase的区别 Archetype和Chunk 相同组件的实体放在一起&#xff0c;也就是我们所说的内存块&#xff08;Chunk&#xff09; Chunk有一个大小 https://blog.csdn.net/weixin_40124181/article/details/103716338 如果批量操作的entity都是同一个chunk下的效率会更…

Oracle(windows安装遇到的ORA-12545、ORA-12154、ORA-12541、ORA-12514等问题)

其实出现该问题就是监听或者服务没有配好。 G:\xiaowangzhenshuai\software\Oracle\product\11.2.0\dbhome_1\NETWORK\ADMINlistener.ora SID_LIST_LISTENER (SID_LIST (SID_DESC (SID_NAME CLRExtProc)(ORACLE_HOME G:\xiaowangzhenshuai\software\Oracle\product\11.2.0\d…

Mac上搭建k8s环境——Minikube

1、在mac上安装Minikube可执行程序 brew cask install minikub 安装后使用minikube version命令查看版本 2、安装docker环境 brew install --cask --appdir/Applications docker #安装docker open -a Docker #启动docker 3、安装kubectl curl -LO https://storage.g…

PostgreSQL 中进行数据导入和导出

在数据库管理中&#xff0c;数据的导入和导出是非常常见的操作。特别是在 PostgreSQL 中&#xff0c;提供了多种工具和方法来实现数据的有效管理。无论是备份数据&#xff0c;还是将数据迁移到其他数据库&#xff0c;或是进行数据分析&#xff0c;掌握数据导入和导出的技巧都是…

【Gitlab】虚拟机硬盘文件丢失,通过xx-flat.vmdk恢复方法

前言 由于近期过年回家&#xff0c;为了用电安全直接手动关闭了所有的电源&#xff0c;导致年后回来商上电开机后exsi上的虚拟机出现了问题。显示我的gitlab虚拟机异常。 恢复 开机之后虚拟机异常&#xff0c;通过磁盘浏览发现gitlab服务器下面的虚拟机磁盘文件只有一个xxx-f…

python的ruff简单使用

Ruff 是一个用 Rust 编写的高性能 Python 静态分析工具和代码格式化工具。它旨在提供快速的代码检查和格式化功能&#xff0c;同时支持丰富的配置选项和与现有工具的兼容性。ruff是用rust实现的python Linter&Formatter。 安装&#xff1a; conda install -c conda-forge…

第16章 Single Thread Execution设计模式(Java高并发编程详解:多线程与系统设计)

简单来说&#xff0c; Single Thread Execution就是采用排他式的操作保证在同一时刻只能有一个线程访问共享资源。 1.机场过安检 1.1非线程安全 先模拟一个非线程安全的安检口类&#xff0c;旅客(线程)分别手持登机牌和身份证接受工作人员的检查&#xff0c;示例代码如所示。…

项目练习:重写若依后端报错cannot be cast to com.xxx.model.LoginUser

文章目录 一、情景说明二、解决办法 一、情景说明 在重写若依后端服务的过程中 使用了Redis存放LoginUser对象数据 那么&#xff0c;有存就有取 在取值的时候&#xff0c;报错 二、解决办法 方法1、在TokenService中修改如下 getLoginUser 方法中&#xff1a;LoginUser u…

简述mysql 主从复制原理及其工作过程,配置一主两从并验证。

MySQL 主从复制工作过程 1、二进制日志记录&#xff08;Binary Logging&#xff09;&#xff1a; 主服务器开启二进制日志记录功能&#xff0c;将所有更改数据的操作&#xff08;如 INSERT、UPDATE、DELETE&#xff09;记录到二进制日志文件中。 2、日志传输&#xff08;Log…

Python Pandas(3):DataFrame

1 介绍 DataFrame 是 Pandas 中的另一个核心数据结构&#xff0c;类似于一个二维的表格或数据库中的数据表。它含有一组有序的列&#xff0c;每列可以是不同的值类型&#xff08;数值、字符串、布尔型值&#xff09;。DataFrame 既有行索引也有列索引&#xff0c;它可以被看做由…

Windows Docker笔记-安装docker

安装环境 操作系统&#xff1a;Windows 11 家庭中文版 docker版本&#xff1a;Docker Desktop version: 4.36.0 (175267) 注意&#xff1a; Docker Desktop 支持以下Windows操作系统&#xff1a; 支持的版本&#xff1a;Windows 10&#xff08;家庭版、专业版、企业版、教育…

Android学习20 -- 手搓App2(Gradle)

1 前言 昨天写了一个完全手搓的&#xff1a;Android学习19 -- 手搓App-CSDN博客 后面谷歌说不要用aapt&#xff0c;d8这些来搞。其实不想弄Gradle的&#xff0c;不过想着既然开始了&#xff0c;就多看一些。之前写过一篇Gradle&#xff0c;不过是最简单的编译&#xff0c;不涉…

团建 蓝桥杯省a 15

问题描述 小蓝正在和朋友们团建&#xff0c;有一个游戏项目需要两人合作&#xff0c;两个人分别拿到一棵大小为 nn 和 mm 的树&#xff0c;树上的每个结点上有一个正整数权值。 两个人需要从各自树的根结点 1 出发走向某个叶结点&#xff0c;从根到这个叶结点的路径上经过的所…

vscode 如何通过Continue引入AI 助手deepseek

第一步&#xff1a; 在deepseek 官网上注册账号&#xff0c;得到APIKeys(deepseek官网地址) 创建属于自己的APIKey,然后复制这个key,(注意保存自己的key)! 第二步&#xff1a; 打开vscode,在插件市场安装Continue插件, 点击设置&#xff0c;添加deepseek模型&#xff0c;默认…

计算机网络——三种交换技术

目录 电路交换——用于电话网络 电路交换的优点&#xff1a; 电路交换的缺点&#xff1a; 报文交换——用于电报网络 报文交换的优点&#xff1a; 报文交换的缺点&#xff1a; 分组交换——用于现代计算机网络 分组交换的优点&#xff1a; 分组交换的缺点 电路交换——…