简易QQ聊天室(多线程通信)

基于控制台实现的简易聊天室,详细实现见代码~

main.cpp(主程序)

#include <iostream>
#include<string>

#include "vol.h"
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

using namespace std;

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
	
	if(!init()){
		cout<<"初始化失败"<<'\n'; 
		return -1;
	}

	Client_connect();
	
	return 0;
}



vol.h(封装函数列表)

#include<iostream>

using namespace std;

bool init();     //网络初始化 
bool Client_connect();     //客户端连接 
void GBKToUTF8(string& strGBK);     //GBK转UTF-8
string UTF8ToGBK(const char* strUTF8){      //UTF-8转GBK
void login();   //客户端登录 
void uiInit(); //初始化聊天室界面 
void gotoxy(int x,int y); //移动光标
//DWORD WINAPI threadFuncRecv(LPCVOID pram);     //接收信息线程 

func.cpp(函数实现)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <stdio.h>
#include <cstring>
#include <string>
#include <conio.h>

#include "vol.h"
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

#define SERVER_IP "118.126.117.125"
#define GROUP_CHAT_PORT 2022

using namespace std;

SOCKET serverSocket;   //网络套接字 
sockaddr_in sockAddr ;   //网络地址 

string nickName;   //昵称 

string line1;	//一行下划线 
string line2;	//一行空白字符串 

HANDLE hMutex;	//互斥锁 

void GBKToUTF8(string& strGBK){		//GBK转UTF-8 
	int len=MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0);
	wchar_t* wszUtf8 = new wchar_t[len];
	memset(wszUtf8, 0, len);
	MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, wszUtf8, len);
	len = WideCharToMultiByte(CP_UTF8, 0, wszUtf8, -1, NULL, 0, NULL, NULL);
	char *szUtf8 = new char[len+1];
	WideCharToMultiByte(CP_UTF8, 0, wszUtf8, -1, szUtf8, len, NULL, NULL);
	strGBK = szUtf8;
	delete[] szUtf8;
	delete[] wszUtf8;
}

string UTF8ToGBK(const char* strUTF8){		//UTF-8转GBK 
	int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8, -1, NULL, 0);
	wchar_t* wszGBK = new wchar_t[len+1];
	memset(wszGBK, 0, len*2+2);
	MultiByteToWideChar(CP_UTF8, 0, strUTF8, -1, wszGBK, len);
	len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
	char* szGBK = new char[len+1];
	memset(szGBK, 0, len+1);
	WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
	string strTemp(szGBK);
	if(wszGBK) delete[] wszGBK;
	if(szGBK) delete[] szGBK;
	return strTemp;
} 

bool init(){
	
	// 1.网络服务的初始化 
	
	WSADATA data;

	int ret=WSAStartup(MAKEWORD(1, 1), &data);

    if(ret!=0)
    {
		cout<<"连接服务器失败,请检查网络连接!"<<'\n';
		return 0;
	}
    
	// 2.创建套接字
	serverSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	 
	// 3.物理地址 
    sockAddr.sin_family = PF_INET;
	sockAddr.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);
	sockAddr.sin_port = htons(GROUP_CHAT_PORT);
	
	//创建互斥锁 
	hMutex =  CreateMutex(0, 0, "console");

	return 1;
}

void login(){
	system("mode con lines=5 cols=30\n");
	cout<<"  欢迎进入翎羽寒星的聊天室"<<"\n\n";
	cout<<"          昵称:";
	cin>>nickName;
	cout<<endl;
	GBKToUTF8(nickName);
	send(serverSocket, nickName.c_str(), nickName.length()+1, 0);
}

void gotoxy(int x,int y){
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); //获取光标 
	COORD pos;
	pos.X=x,pos.Y=y;
	SetConsoleCursorPosition(hOut , pos); //修改光标位置 
} 

void uiInit(){
	system("mode con lines=36 cols=110");
	system("cls");
	gotoxy(0,33);
	for(int i=0;i<110;i++)line1+="-";
	cout<<line1<<endl; 
	for(int i=0;i<110;i++)line2+=" "; 
}	

int cnt=0;

void printMsg(const char* msg){ 	//	打印接收到的信息
	//上锁(申请互斥锁)
	//INFINITE,表示如果没有申请到资源,就一直等待,直到等到为止! 
	WaitForSingleObject(hMutex, INFINITE); 
	
	static POINT pos = {0, 0};	//static是静态变量,只有第一次会被赋值,函数结束后不会消失 	
	
	gotoxy(pos.x,pos.y);
	
	srand(time(0));
	
	int col=rand()%5+31;
	
	printf("\033[0;%d;40m%s\033[0m\n", col, msg);        //显示颜色字符串
	
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);        //记录消息坐标
	CONSOLE_SCREEN_BUFFER_INFO info;
	GetConsoleScreenBufferInfo(hOut, &info);
	pos.x = info.dwCursorPosition.X;
	pos.y = info.dwCursorPosition.Y;
	
	if(pos.y>=33){            //实现滚动效果
		cout<<line2<<endl;
		cout<<endl<<endl;
		gotoxy(0, 33);
		cout<<line1<<endl;
		pos.y-=1;
	}
	
	gotoxy(1,34);
	
	//释放锁
	ReleaseMutex(hMutex);
}

void editPrint(int col,char ch){		//编辑区字符打印 
	WaitForSingleObject(hMutex, INFINITE);
	
	gotoxy(col,34);
	cout<<ch;
	
	ReleaseMutex(hMutex); 
}


void editPrint(int col,string str){		//编辑区字符串打印 
	WaitForSingleObject(hMutex, INFINITE);
	
	gotoxy(col,34);
	cout<<str;
	
	ReleaseMutex(hMutex); 
}


DWORD WINAPI threadFuncRecv(LPVOID pram){   //创建接收信息线程 

	char buff[4096];
	while(1){
		int ret = recv(serverSocket, buff, sizeof(buff), 0);
		if(ret<=0){
			cout<<"服务器关闭或故障!"<<endl; 
			break;
		}
		
		// 打印接收到的信息
		// to do. 
		printMsg(UTF8ToGBK(buff).c_str()); 
	}
		 
	return 0;
}

bool is_HZ(char str[], int index){
	//一个汉字两个字节  第一个字节<0  第二个字节  <0 or >0
	//一个英文字符,  只有一个字节,   >0
	
	int i=0;
	while(i<index){
		if(str[i]>0){
			i++;
		}else{
			i+=2;
		}
	} 
	
	return i>index;
}

bool Client_connect(){
	
	int ret = connect(serverSocket, (SOCKADDR*)&sockAddr, sizeof(sockAddr));
	
	if(ret!=0){
		cout<<"连接服务器失败,请检查网络连接!"<<'\n';
		return -1;
	}
	
	login();
	
	uiInit(); //初始化聊天室界面 
	
	HANDLE hTread = CreateThread(0, 0, threadFuncRecv, 0, 0, 0);
	
	CloseHandle(hTread);
	
	//编辑信息 
	while(1){
		char buff[1024];
		memset(buff, 0, sizeof(buff));
		editPrint(0 , '>');
		int len=0; 
		while(1){
			if(_kbhit()){		//判断有无按键输入 
				char ch = getch();		//换行也能读入
				if(ch == '\r')break;		//按下了回车键 
				else if(ch == 8){
					if(is_HZ(buff, len-1)){
						editPrint(len+1, "\b\b  \b\b");
						buff[len-1] = 0;
						buff[len-2] = 0;
						len-=2;
					}else{
						editPrint(len+1, "\b \b");
						buff[len-1] = 0;
						len-=1;
					}
					continue;
				}	
				
				WaitForSingleObject(hMutex, INFINITE);
				
				do{
					cout<<ch;
					buff[len++] = ch;
				} while(_kbhit()&&(ch=getch()));		//连续读入,解决中文输入问题 
				
				ReleaseMutex(hMutex);
			}
		}

		if(len == 0)continue;
	 
		//清除编辑区的信息 
		editPrint(0, line2);
		
		//把用户自己的话,输出到聊天室
		char buff2[1024];
		memset(buff2, 0, sizeof(buff2));
		//char数组转字符串 
		string ss = "[LocalHost@"+UTF8ToGBK(nickName.c_str())+"]"+string(&buff[0],&buff[len]);	
		//字符串转char数组 
		strncpy(buff2, ss.c_str(), ss.length());
		printMsg(buff2); 
		
		//发送编辑好的信息
		send(serverSocket, buff, strlen(buff)+1, 0); 
		
	}
	 
	
	// 编辑信息
	// to do. 

	return 1;
}









完美实现~,使用devc++中文显示有点儿小bug,欢迎大佬帮忙改进~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值