c++多线程实现的socket聊天室代码,可开多个客户端。

编程入门 行业动态 更新时间:2024-10-10 04:27:22

c++多线程实现的socket聊天室代码,可开<a href=https://www.elefans.com/category/jswz/34/1771377.html style=多个客户端。"/>

c++多线程实现的socket聊天室代码,可开多个客户端。

代码很乱,不建议仔细研究,需要讲解可留评论。
运行截图:

服务器的极简版:

	
#include"winsock2.h"
#include"WS2tcpip.h"  //本程序用到地址转换函数inet_pton(),所以要包含该头文件
#include"process.h"
#include<windows.h>
using namespace std;int main()
{WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){return 0;}//这一部分确定协议,端口,ip地址sockaddr_in addr, client_addr;int addr_length = sizeof(sockaddr);addr.sin_family = AF_INET;addr.sin_port = htons(12345);addr.sin_addr.s_addr = htonl(INADDR_ANY);//这一部分按套路等待连接SOCKET m_socket = socket(AF_INET, SOCK_STREAM, 0);bind(m_socket, (sockaddr*)&addr, addr_length);listen(m_socket, SOMAXCONN);accept(m_socket, (sockaddr*)&client_addr, &addr_length);//这一部分关闭连接closesocket(m_socket);WSACleanup();return 0;
}

实现虚拟机向本机通信,好像是桥接模式下?忘了。
Linux(虚拟机下)客户端极简版:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include<string>
#include<iostream>
using namespace std;
int main(int argc,char *argv[])
{// first step create socket int sockfd;if ( (sockfd = socket(AF_INET,SOCK_STREAM,0))==-1) { perror("socket"); return -1; }// second step: send request to server for connectionstruct sockaddr_in servaddr;memset(&servaddr,0,sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(12345); // server's portservaddr.sin_addr.s_addr=inet_addr("192.168.17.120");//server's ipif (connect(sockfd, (struct sockaddr *)&servaddr,sizeof(servaddr)) != 0)  // send request to server for connection{ perror("connect"); close(sockfd); return -1; }char buffer[1024];// 3th step connect with server while(1){int iret;memset(buffer,0,sizeof(buffer));int choice;printf("if you want to continue to chat please input 1 or input else\n");printf("please input what you want to say\n");cin>>buffer;     printf("send: %s\n",buffer);send(sockfd,buffer,strlen(buffer),0);}close(sockfd);
}

Server:

#include<iostream>
#include"winsock2.h"
#include"WS2tcpip.h"  //本程序用到地址转换函数inet_pton(),所以要包含该头文件
#include"process.h"
#include<windows.h>
#include<vector>
#include<thread>
#include<set>
//#include<future>
#define PORT 65432    //定义要访问的服务器端口常量
#define MSG_SHOW 1
#define MSG_CREATE 2
#define MSG_JOIN 3
#define MSG_LEAVE 4
#define MSG_QUIT 5
#define MSG_EXIT 5
#define MSG_TALK 6
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int writefile(char* num, HANDLE fileHandle);
DWORD d1 = 0;class MsgHead {
public:int msgType;int	dataLength;
};
class MsgShow :public MsgHead
{
public:MsgShow() {msgType = MSG_SHOW;dataLength = sizeof(MsgShow);}};
class MsgCreate :public MsgHead
{
public:MsgCreate() {msgType = MSG_CREATE;dataLength = sizeof(MsgCreate);}};
class MsgJoin :public MsgHead
{public:int number;MsgJoin(int number) {msgType = MSG_JOIN;dataLength = sizeof(MsgJoin);this->number = number;}
};
class MsgLeave :public MsgHead
{
public:MsgLeave() {msgType = MSG_LEAVE;dataLength = sizeof(MsgLeave);}};
class MsgExit :public MsgHead
{
public:MsgExit() {msgType = MSG_QUIT;dataLength = sizeof(MsgExit);}};
class MsgTalk :public MsgHead
{char buff[1024];
public:MsgTalk() {memset(buff, '\0', sizeof(buff));msgType = MSG_TALK;dataLength = sizeof(MsgTalk);}char* getBuff() {return buff;}
};
vector<set<SOCKET>> vecMsgCreate;
void dealWithData(MsgHead* msg,SOCKET sClient) {if (msg->msgType == MSG_SHOW) {cout << "显示聊天室" << endl;int identifier = 1;for (vector<set<SOCKET>>::iterator it = vecMsgCreate.begin();it != vecMsgCreate.end();it++){cout << "**********聊天室: " << identifier <<" ********" << endl;cout << " 用户: " << endl;for (set<SOCKET>::iterator j = it->begin();j != it->end();j++){cout <<' '<< * j << endl;}cout << "*****************************" << endl;identifier++;}}else if (msg->msgType == MSG_CREATE){cout << "创建聊天室" << endl;set<SOCKET> S;S.insert(sClient);vecMsgCreate.push_back(S);}else if (msg->msgType ==  MSG_JOIN) {cout << "加入聊天室" << endl;int number = ((MsgJoin*)msg)->number;vecMsgCreate[number - 1].insert(sClient);//vector<set<SOCKET>>::iterator it = vecMsgCreate[number - 1].begin();}else if (msg->msgType == MSG_LEAVE) {cout << "离开聊天室" << endl;}else if ((msg->msgType == MSG_QUIT ) || (msg->msgType ==  MSG_EXIT)) {cout << "退出" << endl;}else if (msg->msgType == MSG_TALK) {//cout << "开始聊天" << endl;//MsgTalk* msgtalk = (MsgTalk*)buff;char *s= ((MsgTalk*)msg)->getBuff();cout << s << endl;for (vector<set<SOCKET>>::iterator it = vecMsgCreate.begin();it != vecMsgCreate.end();it++){if (it->find(sClient)!=it->end()){for (set<SOCKET>::iterator j = it->begin();j != it->end();j++){if (*j != sClient){send(*j, (const char*)msg, 1000, 0);}}}}}
}int main()
{	//MessageBox(NULL,TEXT("点击确定运行程序"), TEXT("hello world"),MB_OK);SOCKET sock_server, newsock;sockaddr_in addr, client_addr;unsigned hThread;/*初始化winsock DLL*/WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){cout << "加载winsock.dll失败!\n";return 0;}//data文件句柄HANDLE hfile = CreateFile(TEXT("..\\..\\data.txt"), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);SetFilePointer(hfile, 0, NULL, FILE_END);/*创建套接字*///	if ((sock_server=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR){cout << "创建套接字失败!" << WSAGetLastError() << endl;WSACleanup();return 0;}/*绑定IP端口*/int addr_len = sizeof(struct sockaddr_in);memset((void*)&addr, 0, addr_len);addr.sin_family = AF_INET;addr.sin_port = htons(PORT);addr.sin_addr.s_addr = htonl(INADDR_ANY);/*给监听套接字绑定地址*/
//	if (bind(sock_server,(LPSOCKADDR)&addr,sizeof(addr))!=0)if (bind(sock_server, (const sockaddr *)&addr, sizeof(addr)) != 0){cout << "绑定地址失败!" << WSAGetLastError() << endl;closesocket(sock_server);WSACleanup();return 0;}/*开始监听*/if (listen(sock_server, 0) != 0){cout << "listen函数调用失败!" << WSAGetLastError() << endl;closesocket(sock_server);WSACleanup();return 0;}else{cout << "listenning......\n";}/*接收并处理客户连接*/FD_SET fd_read; //fd_set 里面放的是socket,是一个socket集合FD_ZERO(&fd_read);FD_SET(sock_server, &fd_read);FD_SET copy(fd_read);while (true) {const timeval tv = { 1,0 }; fd_read = copy;//cout << fd_read.fd_count << endl;int ret = select(NULL, &fd_read, NULL, NULL, &tv);//select会识别有没有网络事件发送,若没有就阻塞在这里。加了个timeval代表让他等一秒就下执行int fdCount = fd_read.fd_count;for (int i = 0;i < fdCount;i++) {if (fd_read.fd_array[i] == sock_server) {sockaddr_in clientAddr;int nlen = sizeof(sockaddr_in);SOCKET sClient = accept(sock_server, (sockaddr*)&clientAddr, &nlen);/* 第一个参数sockfd为服务器的socket描述字,第二个参数addr为指向struct sockaddr* 的指针,用于返回客户端的协议地址,第三个参数addrlen为协议地址的长度。*/if (sClient == SOCKET_ERROR) {cout << "接收客户端失败" << endl;closesocket(sock_server);return -1;}else cout << "连接客户端成功" << endl;FD_SET(sClient, &fd_read);FD_SET(sClient, &copy);}else {char msg[1024];memset(msg, '\0', sizeof(msg));int res = recv(fd_read.fd_array[i], msg, 1000, 0);//for (auto j : copy.fd_array) {   //向其他客户端发送的消息//	if (j != sock_server && j != fd_read.fd_array[i]) {//		send(j, msg, 1000, 0);//	}//}/***********向data.txt文件写入数据*************/char* s;s = ((MsgTalk*)msg)->getBuff();writefile(s, hfile);/***********************************************/dealWithData((MsgHead *)msg,fd_read.fd_array[i]);if (res <= 0) {FD_CLR(fd_read.fd_array[i], &copy);cout << "用户退出" << endl;break;}}}} closesocket(newsock);CloseHandle(hfile);closesocket(sock_server);WSACleanup();return 0;
}void tcpsend(void* par)
{int size;SOCKET sock = (SOCKET)par;while (true){char msg[1000];memset(msg, '\0', sizeof(msg));if ((size = recv(sock, msg,99, 0)) < 0){cout << "接收信息失败,错误码:" << WSAGetLastError() << endl;break;}else if (size == 0){break;}else   //输出收到的数据{//将数据中的整型数据字段的值由网络字节顺序转换为主机字节顺序//stud.examination = htonl(stud.examination);cout << "收到的消息:" << msg << endl;}}
}int writefile(char* num,HANDLE fileHandle) {BOOL bRet = WriteFile(fileHandle, num, strlen(num), &d1, NULL);char c = '\n';if (!bRet) {int w = GetLastError();MessageBox(NULL, TEXT("数据写入失败"), TEXT("标头"), MB_OK);return w;}bRet = WriteFile(fileHandle, &c,1, &d1, NULL);return 0;
}

Client:

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <iostream>
#include <thread> 
#include<vector>
#include<queue>
#include<string>
#include<mutex>
#include<future>
#define PORT 65432
#define MSG_SHOW 1
#define MSG_CREATE 2
#define MSG_JOIN 3
#define MSG_LEAVE 4
#define MSG_QUIT 5
#define MSG_EXIT 5
#define MSG_TALK 6
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
class MsgHead {
public:int msgType;int	dataLength;
};
class MsgShow:public MsgHead
{
public:MsgShow() {msgType = MSG_SHOW;dataLength = sizeof(MsgShow);}};
class MsgCreate :public MsgHead
{
public:MsgCreate() {msgType = MSG_CREATE;dataLength = sizeof(MsgCreate);}};
class MsgJoin :public MsgHead
{public:MsgJoin(int number) {msgType = MSG_JOIN;dataLength = sizeof(MsgJoin);this->number = number;}int number;
};
class MsgLeave :public MsgHead
{
public:MsgLeave() {msgType = MSG_LEAVE;dataLength = sizeof(MsgLeave);}};
class MsgExit :public MsgHead
{
public:MsgExit() {msgType = MSG_EXIT;dataLength = sizeof(MsgExit);}};
class MsgTalk :public MsgHead
{char buff[1024];
public:MsgTalk() {memset(buff, '\0', sizeof(buff));msgType = MSG_TALK;dataLength = sizeof(MsgTalk);}char* getBuff() {return buff;}
};
LPVOID chat(LPVOID ptr) {SOCKET sClient = *(SOCKET*)ptr;cout << "please input: show create join leave exit/quit" << endl;while (1) {char buff[1024];gets_s(buff);  //会清掉最后输的换行符if (strcmp(buff, "show") == 0) {MsgShow msgShow;send(sClient, (const char*)&msgShow, msgShow.dataLength, 0);//显示聊天室}else if (strcmp(buff, "join") == 0) {cout<<"输入数字进行选择:" << endl;int number;cin >> number;MsgJoin msgJoin(number);send(sClient, (const char*)&msgJoin, msgJoin.dataLength, 0);//加入一个聊天室}else if (strcmp(buff, "create") == 0) {MsgCreate msgCreate;send(sClient, (const char*)&msgCreate, msgCreate.dataLength, 0);//创建一个聊天室 }else if (strcmp(buff, "talk") == 0) {cout << "开始聊天" << endl;MsgTalk msgTalk;while (1) {gets_s(msgTalk.getBuff(), 1000);send(sClient, (const char*)&msgTalk, msgTalk.dataLength, 0);}}}
}int main() {/*定义相关变量*/int sock_client;							//定义客户端套接字struct sockaddr_in server_addr;				//定义存放服务器端地址的结构变量int addr_len = sizeof(struct sockaddr_in);	//地址结构变量长度/*初始化*/WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){cout << "加载winsock.dll失败!\n";return 0;}/*创建套接字*/if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) < 0){cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;WSACleanup();return 0;}/*输入服务器IP地址以及填写服务器地址结构*/char IP[20];cout << "请输入服务器地址:";cin >> IP;memset((void*)&server_addr, 0, addr_len);//地址结构清零server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);in_addr a;inet_pton(AF_INET, IP, &a);server_addr.sin_addr.s_addr = a.S_un.S_addr;//服务器IP地址/*Connecting Server*/SOCKET_ERROR;if (connect(sock_client, (struct sockaddr*)&server_addr, addr_len) != 0){cout << "Connecting Error!!" << WSAGetLastError() << endl;closesocket(sock_client);WSACleanup();return 0;}//chat(&sock_client);future<HANDLE> futureResult = async(chat,&sock_client);while (1) {char buff[1000];int ret = recv(sock_client, buff, 1024, 0);if (ret > 0) {cout << ((MsgTalk*)buff)->getBuff() << endl;}else {cout << "客户端接收数据失败" << endl;}}//HANDLE = futureResult.get();//WaitForSingleObject();closesocket(sock_client);WSACleanup();return 0;
}

更多推荐

c++多线程实现的socket聊天室代码,可开多个客户端。

本文发布于:2024-03-12 13:44:17,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1731644.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:多个   多线程   客户端   聊天室   代码

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!