当前位置: 首页 > article >正文

网络编程day2-套接字与TPC服务器与客户端的搭建

1.思维导图

2. TPC服务器与客户端的搭建

要点:动态协议包防止粘包

服务器

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;

enum Type
{
	TYPE_REGIST,//注册
	TYPE_LOGIN  //登录
};

typedef struct Pack
{
	int size;
	enum Type type;
	char buf[2048];
	int count;
}pack_t;

void read_pack(pack_t* pack)
{
	char* buf=pack->buf;
	int readed_size = 0;
	while(1)
	{
		short data_size = *(short*)(buf+readed_size);
		if(data_size==0)
		{
		//	printf("数据解析完毕\n");
			break;
		}
		readed_size+=2;
		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;
	}
	// ./server 7777
	int port=atoi(argv[1]);//将字符串 7777 转换为int 类型port
	//创建服务器套接字
	int server = socket(AF_INET,SOCK_STREAM,0);
	//准备网络地址结构体:struct sockaddr_in
	addr_in_t addr={0};
	addr.sin_family = AF_INET;//固定
	addr.sin_port=htons(port);//port转换为网络字节序
	addr.sin_addr.s_addr = inet_addr("0.0.0.0");//ip转换为unsigned int
	
	//为服务器套接字绑定ip和port
	if(bind(server,(addr_t*)&addr,sizeof(addr))==-1)//需要强转
	{
		perror("bind");
		return 1;
	}
	//监听
	listen(server,10);
	//接受客户端的连接
	addr_in_t cilent_addr={0};
	int cilent_addr_len =sizeof(cilent_addr);
	int cilent = accept(server,(addr_t*)&cilent_addr,&cilent_addr_len);//需要强转
	if(cilent!=-1)
	{
		printf("有客户端连接\n");
	}
	//读取客户端发来的消息
	while(1)
	{
		int pack_size=0;
		read(cilent,&pack_size,4);//先读取size
		pack_t pack={0};
	    int res=read(cilent,(char*)&pack+4,pack_size-4);//读取size后的内容
		if(res==0)
		{
			printf("客户端断开连接\n");
			break;
		}
		pack.size=pack_size;//给新创建的size赋值

		read_pack(&pack);
	}
	return 0;
}

客户端

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;

enum Type
{
	TYPE_REGIST,//注册
	TYPE_LOGIN  //登录
};

typedef struct Pack//协议包
{
	int size; //用来记录整个协议包的实际大小,占四个字节  定长部分
	enum Type type;//占4个字节  变长部分
	char buf[2048];//占count个字节  不传输部分
	int count;//用来记录指针的偏移量,也就是buf使用了多少字节
}pack_t;

void append(pack_t* pack,const char* data)
{
	char* buf=pack->buf;
	int len=strlen(data);

	*(short*)(buf+pack->count)=len;//将buf的前两个字节当做short来存储数据len
	pack->count+=2;//偏移两个字节
	
	memcpy(buf+pack->count,data,len);//把数据内容拷贝到buf中
	pack->count+=len;//偏移数据长度个字节

	pack->size=pack->count+8;
}

int main(int argc, const char *argv[])
{
	if(argc!=2)
	{
		printf("请输入端口号:\n");
		return 1;
	}
	int port=atoi(argv[1]);//获取端口号
	int cilent=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.217.128");

	if(connect(cilent,(addr_t*)&addr,sizeof(addr))==-1)//连接服务器
	{
		perror("connect");
		return 1;
	}

	while(1)
	{
		pack_t pack={0};
		char name[20]="";
		char pswd[20]="";

		pack.type=TYPE_REGIST;
		printf("请输入账号:");
		scanf("%20s",name);
		while(getchar()!=10);
		printf("请输入密码:");
		scanf("%20s",pswd);
		while(getchar()!=10);

		append(&pack,name);
		append(&pack,pswd);

		write(cilent,&pack,pack.size);//type占了四个字节
	}

	return 0;
}


http://www.kler.cn/a/537620.html

相关文章:

  • (七)C++的异常和文件输入与输出
  • 文件上传到腾讯云存储、签名及设置过期时间
  • RestTemplate Https 证书访问错误
  • C++设计模式
  • 4.python+flask+SQLAlchemy+达梦数据库
  • 排序算法--基数排序
  • 什么是java中的线程同步
  • 【Python实战练习】Python类中的方法:形式与作用详解
  • 三次方程的几何新视界:双曲线-抛物线交点法与旋转圆系法
  • 去除 RequestTemplate 对象中的指定请求头
  • 优惠券平台(十二):EasyExcel解析实现用户优惠券分发(2)
  • 未来AI医院蓝图:源码、机器人与数字孪生如何打造智能医疗APP?
  • ArcGIS技术与土地利用分析全流程实践----从数据管理到建模预测
  • AIGC-PPT创作智能体完整指令(DeepSeek,豆包,千问,Kimi,GPT)
  • 基于ssm的药店管理系统
  • 第26场蓝桥入门赛
  • AI绘画社区:解锁艺术共创的无限可能(9/10)
  • OnlyOffice docker 运行(详细)
  • CS架构软件网络安全 csf网络安全框架
  • Thymeleaf在循环时设置递增序号
  • 数据可视化基本套路总结
  • CNN-day7-经典神经网络VGG
  • 鸿蒙harmony 手势密码
  • MHTML文件如何在前端页面展示
  • 天润融通智能扩写工具如何让AI客服机器人更高效?
  • 【大数据技术】搭建完全分布式高可用大数据集群(ZooKeeper)