C C++最全网络编程:json多客户端服务器实现_多客户端网络服务器实现(1),2024年最新美团C C++开发工程师岗位职能要求

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include “cJSON.h”
#include <stdbool.h>
#define MAXSIZE 100

void *client_thread(void *arg);
sem_t sm;//定义一个信号量

struct ClientInfo{

int sockfd;//套接字
char id[16];

};

/*定义一个结构体数组
作用:来一个客户端,就把客户端的信息存在这个数组里面
memset()对其初始化*/
struct ClientInfo cinfo[MAXSIZE];

int main(void)
{
//初始化信号量:wq
sem_init(&sm, 0, 0);

//1.创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
	perror("socket fail");
	return -1;
}

//2.绑定
struct sockaddr_in addr;  //定一个存储地址,端口号的替代结构体
//struct sockaddr\_in \*p = (struct sockaddr\_in\*)&addr;
memset(&addr, 0, sizeof(addr)); //初始化为0
addr.sin_family = AF_INET;//初始化地址族IPV4
addr.sin_port = htons(8989); //设置端口号(网络字节序号)
addr.sin_addr.s_addr = INADDR_ANY;//初始化绑定地址, 用INADDR\_ANY--表示绑定本机地址
int ret = bind(sockfd, (struct sockaddr\*)&addr, sizeof(addr));
if(ret < 0)
{
	perror("bind fail:");
	return -1;
}

//3.监听
ret = listen(sockfd, 5);
if(ret < 0)
{
	perror("listen error");
	return -1;
}

//4.接受链接, 没有客户端链接的时候->此函数阻塞
struct sockaddr_in clientaddr; //保存客户端地址
socklen_t len = sizeof(clientaddr);//保存地址长度

//初始化客户端信息结构体数组
memset(cinfo, 0, sizeof(cinfo));//所有数据都清零

//主线程只负责接受客户端链接,不收发数据->收发数据在线程中实现
while(1)
{
	int clientfd = accept(sockfd, (struct sockaddr\*)&clientaddr, &len);
	if(clientfd < 0)
	{
		perror("accept error");
		return -1;
	}

	//创建一个线程
	pthread_t id = 0;
	pthread\_create(&id, NULL, client_thread, (void \*)&clientfd);
	//分离线程
	pthread\_detach(id);

	//把客户端套接字描述符保存(链表, 数组)
	//把套接字保存在最小未使用的数组元素中
	for(int i=0; i<MAXSIZE; i++)
	{
		if(cinfo[i].sockfd == 0)
		{
			cinfo[i].sockfd = clientfd;//保存客户端套接字
			break;
		}
	}
	//获取信号量资源
	sem\_wait(&sm);//目的是等待->线程执行完int clientfd = \*((int \*)arg)这句再循环上面的内容
}

sem\_destroy(&sm);//销毁信号量
//关闭套接字
close(sockfd);
return 0;

}

/*
json数据格式:通用
作用:解析{“id”:“99999”, “to”:“88888”, data:“hello world”}此对象
这对象的99999/888888/helloworld等字符串
(用字符串方法解析比较麻烦)
*/
bool parse_data(char *srcData, char *fromid, char *toid, char *data)
{
//字符串转cjson对象
cJSON *root = cJSON_Parse(srcData);
if(root == NULL) return false;
//解析to
cJSON *toObj = cJSON_GetObjectItem(root,“to”); //根据键获取对应的值
printf(“toId:%s\n”, toObj->valuestring);
sprintf(toid, “%s”, toObj->valuestring);

//解析id
cJSON \*idObj = cJSON\_GetObjectItem(root,"id"); //根据键获取对应的值
printf("Id:%s\n", idObj->valuestring);
sprintf(fromid,"%s", idObj->valuestring);
//解析to
cJSON \*dataObj = cJSON\_GetObjectItem(root,"data"); //根据键获取对应的值
printf("data:%s\n", dataObj->valuestring);
sprintf(data, "%s", dataObj->valuestring);
cJSON\_Delete(root);//释放
return true;

}

//线程-收发数据
void *client_thread(void *arg)
{
int clientfd = *((int *)arg); //传套接字过来,再转int型
//释放信号量资源
sem_post(&sm);
char recvbuffer[1024]={0};
char fromid[16]; //保存发送方id
char toid[16]; //保存接收方id
char data[128];//要发送的数据
while(1)
{
//第一次读取时候给服务器上报id(登录)->存起来和套接字绑定在一起
//{“id”:“99999”, “to”:“88888”, data:“hello world”};
int ret = read(clientfd, recvbuffer, 1024);
if(ret <= 0)
{
printf(“客户端%d掉线\n”, clientfd);
//把链表或数组中的套接字描述符要清理
break;
}

	//解析
	parse\_data(recvbuffer, fromid, toid, data);



	//注册或者登陆要获取套接字里的id信息->从数组中查到套接字,所以对应的id
	//当第一次链接的时候id不存在要自己添加
	for(int i=0; i<MAXSIZE; i++)
	{
		if(cinfo[i].sockfd == clientfd && strlen(cinfo[i].id)==0)
		{
			strcpy(cinfo[i].id, fromid);
			
			//发送反馈信息{type:0};
			
			break;
		}
	}
	
	//通过to对应的id号找到对应用套接字->套接字才能发数据
	for(int i=0; i<MAXSIZE; i++)
	{
		
		if(cinfo[i].sockfd != 0  && strcmp(cinfo[i].id, toid)==0)
		{
			
			char tmpbuffer[1024]={0};
			sprintf(tmpbuffer, "{\"type\":\"2\",\"from\":\"%s\",\"data\":\"%s\"}", fromid, data);
			//发送数据
			write(cinfo[i].sockfd, tmpbuffer, strlen(tmpbuffer)+1);
			//发送反馈信息{type:1}
			break;
		}
	}
	printf("[clientfd=%d]%s\n",clientfd,  recvbuffer);
	//解析接收到的数据, 从链表或数组中找到对应用套接字描述符再发送数据
}

}

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值