c++聊天小程序

纯c++写的聊天小程序

涉及的技术

  1. c++ socket
  2. c++ stl
  3. c++ thread

设计的原理
以一个结构体的形式存储客户端,用vector存取存在的客户端,开启多线程处理逻辑

效果
在这里插入图片描述
源代码
server

#include<thread>
#include <WinSock2.h>
#include<iostream>
#include<vector>
#include <csignal>
#include<exception>

#pragma comment(lib,"ws2_32.lib")

using namespace std;
int myStrLen(char* str)
{
   
	int i = 0;
	while (*str != '\0')
	{
   
		i++;
		str++;
	}
	return i;
}
char* myStrcat(char *str1, char* str2)
{
   
	char *temp = str1;
	while (*temp != '\0')temp++;
	while ((*temp++ = *str2++) != '\0');
	return str1;
}
char *myStrcp(char *str1, char* str2)
{
   
	char *temp = str1;
	while ((*temp++ = *str2++) != '\0');
	return str1;
}
bool myStrSame(char *str1, char *str2)
{
   
	if (myStrLen(str1) != myStrLen(str2))return false;
	for (int i = 0; i<myStrLen(str1); i++)
	if (*str1++ != *str2++)return false;
	return true;
}
char * myStrSplit(char *str1, char *str2, char *str3, char sp)
//参数:姓名,需要分解信息,得到信息,分隔符
{
   
	char *temp = str1;
	int i = 0;
	while ((*str3++ = *str2++) != sp)i++;
	while ((*temp++ = *str2++) != '\0');
	*(--str3) = '\0';
	return str3;
}
//start set global variable
SOCKET ServerSocket = INVALID_SOCKET;//服务端套接字
SOCKET ClientSocket = INVALID_SOCKET;//客户端套接字
SOCKADDR_IN ServerAddr = {
    0 };//服务端地址
SOCKADDR_IN ClientAddr = {
    0 };//客户端地址
USHORT uPort = 10001;//服务器监听端口
int iClientAddrLen = sizeof(ClientAddr);

struct Client
{
   
	SOCKET client_socket;
	char clint_name[255];
};
Client temp_client;
vector<Client> clients;

char buffer[4096] = {
    0 };
int iRecvLen = 0;
int iSendLen = 0;
char msg_type = '#';
//end set global variable
//msg type
//# name 
//$ show online user
//info@xx send info to xx
//& is exit


bool showClients()
//查看在线的用户
{
   
	if (clients.size() == 0)
	{
   
		cout << "online users is null\n";
		return false;
	}
	cout << "online uses are:\n";
	for (auto it = clients.begin(); it < clients.end(); it++)
		cout << it->clint_name << endl;
	return true;
}

void deleteClient(char *name)
//离开的客户端进行处理
{
   
	for (auto it = clients.begin(); it < clients.end(); it++)
	{
   
		if (myStrSame(name,it->clint_name))
		{
   
			clients.erase(it);
			cout << "delete client  "<<name<<" success\n";
			return;
		}
	}
	//cout << "delete client fail\n";
}

int startServer()
//打开服务器
{
   
	//存放套接字信息的结构
	WSADATA wsaData = {
    0 };
	//初始化套接字
	if (WSAStartup(MAKEWORD(2, 2), &wsaData))
	{
   
		printf("WSAStartup failed with error code: %d\n", WSAGetLastError());
		return -1;
	}
	//判断版本
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
   
		printf("wVersion was not 2.2\n");
		return -1;
	}
	//创建套接字
	ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (ServerSocket == INVALID_SOCKET)
	{
   
		printf("socket failed with error code: %d\n", WSAGetLastError());
		return -1;
	}

	//设置服务器地址
	ServerAddr.sin_family = AF_INET;//连接方式
	ServerAddr.sin_port = htons(uPort);//服务器监听端口
	ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//任何客户端都能连接这个服务器

	//绑定服务器
	if (SOCKET_ERROR == ::bind(ServerSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)))
	{
   
		printf("bind failed with error code: %d\n", WSAGetLastError());
		closesocket(ServerSocket);
		return -1;
	}
	if (SOCKET_ERROR == listen(ServerSocket, 20))
	{
   
		printf("listen failed with error code: %d\n", WSAGetLastError());
		closesocket(ServerSocket);
		WSACleanup();
		return -1;
	}
	cout << "starting server...\n";
	return 0;

}


bool isExistClient(char *name)
//判断客户端是否存在在clients中
{
   
	for (auto it = clients.begin(); it < clients.end(); it++)
	{
   
		if (myStrSame(name, it->clint_name))return true;
	}
	return false;
}

void sendMessage(Client * client,char * message,char *name)
//发送消息,目的地的name,以及信息message,转发的消息格式:message+@+sender name
{
   
	char buf[2048] = {
    0 };
	buf[0] = '\0';
	myStrcat(buf, message);
	myStrcat(buf, "@");
	myStrcat(buf, client->clint_name);
	int ret = 0;
	//寻找目的客户端,开始发送信息
	for (auto it = clients.begin(); it < clients.end(); it++)
	{
   
		if (myStrSame(name, it->clint_name))
		{
   
			ret = send(it->client_socket, buf, myStrLen(buf), 0);
			break;
		}
	}
	if (SOCKET_ERROR == ret)
	{
   
		printf("send failed with error code: %d\n", WSAGetLastError());
		deleteClient(client->clint_name);
		WSACleanup();
	}
	else
	{
   
		cout << client->clint_name << " to " << name << " send :" << buf << endl;
		buf[0] = '\0';
	}
}

void recvMessage(Client *clinet)
//读取客户端的消息
{
   
		char buf[1024] = {
    0 };
		int ret = 0;
		memset(buf, 0, sizeof(buf));	
		ret = recv(clinet->client_socket, buf, sizeof(buf), 0);

		if (SOCKET_ERROR == ret)
		{
   			
			deleteClient(clinet->clint_name);
			//printf("recv failed with error code: %d\n", WSAGetLastError());
			return;
		}
		else
		{
   
			char judge_type = buf[myStrLen(buf) - 1];
			buffer[myStrLen(buf) - 1] = '\0';
			switch (judge_type)
			{
   
			case '#'
  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值