采用TCP协议搭建服务器和客户端

一、创建TCP 服务器流程图

二、创建 TCP 客户端流程图

三、搭建服务器和客户端间双向交流模型

#include <my_head.h>
typedef struct pack
{
	int size;
	char buf[4096];
	int used;
}pack_t;

//将数据添加到数据包
void pack_append_data(pack_t* pack,const char* val)
{
	//buf前两个字节用于存储数据字节大小
	char *buf=pack->buf;

	//计算传输数据长度
	short len = strlen(val);

	//buf的前两个字节存储数据长度
	*(short *)(buf+pack->used) = len;
	pack->used += 2;
	
	//buf前两个字节用于存储数据字节大小
	//将字符串存储在buf的后续内存中
	strcpy(buf+pack->used,val);
	pack->used += len ;

	pack->size = 4 + pack->used;
}

//采用指针数组解包数据
char** read_data_from_pack(pack_t* pack)
{
	//定义字符针,指向pack中的buf
	char* buf = pack->buf;

	//定义指针数组,并在堆区为其申请空间
	char** data = (char**)calloc(20,sizeof(char*));
	if(NULL == data)
	{
		printf("指针数组堆区空间申请失败\n");
	}
	//对data数组进行清零
	bzero(data,20*sizeof(char*));

	//定义标记位
	//记录已读取数据字节大小
	int read_size = 0;
	int i = 0;

	while(read_size < pack->size -8)
	{
		//前两个字节用于记录数据字节大小,不取
		short size = *(short*)(buf + read_size);
		read_size += 2;
		if(size<=0 || read_size + size >pack->size-4)
		{
			printf("无效数据长度\n");
			return NULL ;
		}

		//定义字符数组用于接收数据
		char temp[size+1];
		memset(temp,0,size+1);

		//将数据拷贝到temp数组中
		strncpy(temp,buf+read_size,size);
		//read_size增加temp的长度
		read_size += strlen(temp);

		//重新为指针数组中的每个指针申请堆区空间
		//之前申请的堆区空间大小为指针的固定字节大小
		data[i] = (char *)calloc(1,size+1);
		//将temp数组中数据拷贝到data[i]中
		strcpy(data[i],temp);

		//i自增
		i++;
	}
	return data;
}

void receive_message(int port);
void send_message(int port);

int main(int argc, const char *argv[])
{
	if(argc<2)
	{
		printf("请输入端口号\n");
		return -1;
	}
	short port = atoi(argv[1]);

	int flag;
	printf("请输入要进行的操作:\n");
	printf("1.接收消息\n");
	printf("2.发送消息\n");
	scanf("%d",&flag);

	switch(flag)
	{
	case 1:
		receive_message(port);
		break;
	case 2:
		send_message(port);
		break;
	default:
		printf("输入错误\n");
		break;
	}
}

//接收消息
void receive_message(int port)
{
	//创建服务器
	int sever = socket(AF_INET,SOCK_STREAM,0);
	if(-1==sever)
	{
		perror("socket failed");
		return ;
	}

	struct sockaddr_in addr = {0};
	addr.sin_family=AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr("0.0.0.0");  // 绑定到所有接口

	if(-1==bind(sever,(struct sockaddr *)&addr,sizeof(addr)))
	{
		perror("bind error");
		close(sever);
		return ;                                                 
	}

	listen(sever,10);  //监控服务器    

	struct sockaddr_in client_addr;  //定义客户端结构体                       
	int client_len=sizeof(client_addr); //获取客户端结构体字节大小

	int client = accept(sever,(struct sockaddr*)&client_addr,&client_len);
	//调用accpet 函数接收客户端发送的数据

	if(-1==client)
	{
		perror("accept failed");
		close(sever);
		return ;
	}
	printf("有客户端连接\n");

    //接收数据包
    while(1)
    {
        int size = 0;
        int res = read(client,&size,4);
		printf("res = %d\n",size);
        if(0 == res)
        {
            printf("客户端断开连接\n");
            close(sever);
            return ;                                                        
        }

        pack_t pack = {0};  //定义数据包,用于接收数据
        pack.size = size;
        res = read(client,(char *)&pack+4,size-4);
		printf("pack.buf=[%s]\n",pack.buf);
        //将客户端中的账号和密码数据存储在pack后续的内存中,其大小为size-4

        //调用解包函数,输出数据
        char** data = read_data_from_pack(&pack);
		printf("接收到消息:\n");
    }

    close(sever);

	return;

}

//发送消息
void send_message(int port)
{
	//创建客户端
	int client = socket(AF_INET,SOCK_STREAM,0);
	if(-1==client)
	{
		perror("socket failed");
		return ;
	}

	struct sockaddr_in addr = {0};
	addr.sin_family=AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr("192.168.141.46");

	connect(client,(struct sockaddr*)&addr,sizeof(addr));

	//发送数据包
	char message[128];
	while(1)
	{
		memset(message,0,sizeof(message)); //数据清零
		printf("请输入消息:\n");
		scanf("%s",message);
		getchar(); //吸收换行符

		pack_t pack = {0};
		pack_append_data(&pack,message);

		write(client,&pack,pack.size);
	}

	close(client);

	return ;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值