真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何使用C++代碼實(shí)現(xiàn)多人聊天室

本篇內(nèi)容介紹了“如何使用C++代碼實(shí)現(xiàn)多人聊天室”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)長期為上千多家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺(tái),與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為簡陽企業(yè)提供專業(yè)的網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì),簡陽網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。

UDP

服務(wù)端代碼:

// Test_Console.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
//

#include "stdafx.h"
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#pragma region 全局變量

SOCKET server;     // 服務(wù)端套接字
sockaddr_in sai_server;   // 服務(wù)端信息(ip、端口)

// 消息格式
struct umsg {
 int type;    // 協(xié)議(1:加入 2:退出 3:發(fā)消息)
 char name[64];   // 用戶名字
 char text[512];   // 文本信息
};

// 客戶端鏈表
typedef struct ucnode {
 sockaddr_in addr;  // 客戶端的地址和端口號(hào)
 umsg msg;    // 客戶端傳來的消息
 ucnode* next;
} *ucnode_t;

#pragma endregion


#pragma region 依賴函數(shù)

// 鏈表插入數(shù)據(jù)
ucnode* insertNode(ucnode* head, sockaddr_in addr,umsg msg) {
 ucnode* newNode = new ucnode();
 newNode->addr = addr;
 newNode->msg = msg;
 ucnode* p = head;
 if (p == nullptr) {
  head = newNode;
 }
 else {
  while (p->next != nullptr) {
   p = p->next;
  }
  p->next = newNode;
 }
 return head;
}

// 鏈表刪除數(shù)據(jù)
ucnode* deleteNode(ucnode* head, umsg msg) {
 ucnode* p = head;
 if (p == nullptr) {
  return head;
 }
 if (strcmp(p->msg.name, msg.name) == 0){
  head = p->next;
  delete p;
  return head;
 }
 while (p->next != nullptr && strcmp(p->next->msg.name, msg.name) != 0) {
  p = p->next;
 }
 if (p->next == nullptr) {
  return head;
 }
 ucnode* deleteNode = p->next;
 p->next = deleteNode->next;
 delete deleteNode;
 return head;
}

#pragma endregion

int main()
{
 cout << "我是服務(wù)端" << endl;

 // 初始化 WSA ,激活 socket
 WSADATA wsaData;
 if (WSAStartup(
  MAKEWORD(2, 2),   // 規(guī)定 socket 版本為 2.2
  &wsaData    // 接收關(guān)于套接字的更多信息
  )) {
  cout << "WSAStartup failed : " << GetLastError() << endl;
 }

 // 初始化 socket、服務(wù)器信息
 server = socket(
  AF_INET,   // IPV4
  SOCK_DGRAM,  // UDP
  0    // 不指定協(xié)議
  );
 sai_server.sin_addr.S_un.S_addr = 0; // IP地址
 sai_server.sin_family = AF_INET;  // IPV4
 sai_server.sin_port = htons(8090);  // 傳輸協(xié)議端口

 // 本地地址關(guān)聯(lián)套接字
 if (bind(
  server,      // 要與本地地址綁定的套接字
  (sockaddr*)&sai_server,  // 用來接收客戶端消息的 sockaddr_in 結(jié)構(gòu)體指針
  sizeof(sai_server)   
  )) {
  cout << "bind failed : " << GetLastError() << endl;
  WSACleanup();
 }

 // 初始化客戶端鏈表
 ucnode* listHead = new ucnode();
 listHead->next = nullptr;
 ucnode* lp = listHead;

 // 監(jiān)聽消息
 while (1) {
  // 接收來自客戶端的消息
  umsg msg;
  int len_client = sizeof(sockaddr);
  recvfrom(
   server,      // 本地套接字
   (char*)&msg,     // 存放接收到的消息
   sizeof(msg),     
   0,        // 不修改函數(shù)調(diào)用行為
   (sockaddr*)&sai_server,  // 接收客戶端的IP、端口
   &len_client     // 接收消息的長度,必須初始化,否則默認(rèn)為0 收不到消息    
  );
  
  // sin_addr 轉(zhuǎn) char[](char[] 轉(zhuǎn) sin_addr 使用 inet_top)
  char arr_ip[20];
  inet_ntop(AF_INET, &sai_server.sin_addr, arr_ip, 16);
  
  // 處理消息(1:用戶登錄,2:用戶退出,3:普通會(huì)話)
  switch (msg.type) {
  case 1: 
   insertNode(listHead, sai_server, msg); 
   cout << "[" << arr_ip << ":" << ntohs(sai_server.sin_port) << "] " << msg.name << ":" << "---登錄---" << endl;
   break;
  case 2:
   deleteNode(listHead, msg);
   cout << "[" << arr_ip << ":" << ntohs(sai_server.sin_port) << "] " << msg.name << ":" << "---退出---" << endl;
   break;
  case 3:
   cout << "[" << arr_ip << ":" << ntohs(sai_server.sin_port) << "] " << msg.name << ":" << msg.text << endl;
   // 更新 msg.text
   lp = listHead;
   while (lp) {
    if (strcmp(lp->msg.name, msg.name) == 0) {
     strncpy(lp->msg.text, msg.text, sizeof(msg.text));
     lp->msg.type = msg.type;
     break;
    }
    lp = lp->next;
   }
   // 向其他客戶端廣播(除自己之外)
   lp = listHead;
   while (lp) {
    if (strcmp(lp->msg.name,"") != 0 && strcmp(lp->msg.name, msg.name) != 0) {
     sendto(
      server,      // 本地套接字
      (char*)&msg,     // 消息結(jié)構(gòu)體
      sizeof(msg),     
      0,        // 不修改函數(shù)調(diào)用行為
      (sockaddr*) & lp->addr,  // 目標(biāo)客戶端地址
      sizeof(lp->addr)
     );
    }
    lp = lp->next;
   }
   break;
  }
 }

 // 禁用 socket
 WSACleanup();

 getchar();
    return 0;
}

客戶端代碼:

// Test_Console_2.cpp : 此文件包含 "main" 函數(shù)。程序執(zhí)行將在此處開始并結(jié)束。
//

#include 
#include 
#include 
#include 
#include 
#include 
#include 

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

using namespace std;

#pragma region 全局變量

SOCKET client;     // 客戶端套接字  
sockaddr_in sai_client;   // 存放客戶端地址、端口
sockaddr_in sai_server;   // 存放服務(wù)端發(fā)送的消息

// 發(fā)送和接收的信息體
struct umsg {
 int type;     // 協(xié)議(1:登錄,2:退出,3:發(fā)消息)
 char name[64];    // 用戶名字
 char text[512];    // 文本
};

#pragma endregion

#pragma region 依賴函數(shù)

// 監(jiān)聽服務(wù)器消息
void recvMessage()
{
 while (1){
  umsg msg;
  int len_server = sizeof(sockaddr);
  int len = recvfrom(client, (char*)&msg,sizeof(msg),0,(sockaddr*)&sai_server,&len_server);
  
  cout << msg.name << ": " << msg.text << endl;
 }
}

#pragma endregion

int main()
{
 cout << "我是客戶端" << endl;

 // 初始化 WSA ,激活 socket
 WSADATA wsaData;
 if (WSAStartup(
  MAKEWORD(2, 2),  // 規(guī)定 socket 版本
  &wsaData   // 接收 socket 的更多信息
  )) {
  cout << "WSAStartup failed : " << GetLastError() << endl;
 }

 // 初始化 socket、客戶端信息
 client = socket(
  AF_INET,  // IPV4
  SOCK_DGRAM,  // UDP
  0    // 不指定協(xié)議
  );
 sai_client.sin_family = AF_INET;         // IPV4
 inet_pton(AF_INET, "192.168.1.105", &sai_client.sin_addr);   // 服務(wù)器 IP地址
 sai_client.sin_port = htons(8090);         // 端口

 // 輸入用戶名
 string name;
 getline(cin, name);

 // 發(fā)送登錄消息
 umsg msg;
 msg.type = 1;
 strncpy_s(msg.name, sizeof(msg.name), name.c_str(), 64);
 strncpy_s(msg.text, sizeof(msg.text), "", 512);
 sendto(
  client,       // 本地套接字
  (char*)&msg,      // 發(fā)送的消息
  sizeof(msg), 
  0,         // 不修改函數(shù)調(diào)用行為
  (sockaddr*) & sai_client,  // 消息目標(biāo)
  sizeof(sai_client)
 );

 // 接收服務(wù)器消息
 HANDLE h_recvMes = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)recvMessage, 0, 0, 0);
 if (!h_recvMes) { cout << "CreateThread failed :" << GetLastError() << endl; }
    
 // 發(fā)送消息
 while (1) {
  string content;
  getline(cin, content);
  
  // 如果是退出消息
  if (content == "quit") {
   msg.type = 2;
   sendto(client, (char*)&msg, sizeof msg, 0, (struct sockaddr*) & sai_client, sizeof(sai_client));
   closesocket(client);
   WSACleanup();
   return 0;
  }

  // 如果是會(huì)話消息
  msg.type = 3;
  strncpy_s(msg.text, sizeof(msg.text), content.c_str(), 512);
  sendto(
   client,       // 本地套接字
   (char*)&msg,      // 要發(fā)送的消息
   sizeof(msg), 
   0,         // 不修改函數(shù)調(diào)用行為
   (sockaddr*) & sai_client,   // 發(fā)送目標(biāo)
   sizeof(sai_client)
  );
 }


    getchar();
    return 0;
}

效果圖:

如何使用C++代碼實(shí)現(xiàn)多人聊天室

TCP

服務(wù)器代碼:

// Test_Console.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
//

#include "stdafx.h"
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#pragma region 全局變量

SOCKET server;    // 本地套接字
sockaddr_in sai_server;  // 存放服務(wù)器IP、端口

// 消息格式
struct umsg {
 int type;    // 協(xié)議(1:登錄,2:退出,3:發(fā)消息)
 char name[64];   // 用戶名字
 char text[512];   // 文本信息
};

// 客戶端信息
struct clientInfo {
 SOCKET client;
 sockaddr_in saddr;
 umsg msg;
};

// 客戶端鏈表
typedef struct ucnode {
 clientInfo cInfo;
 ucnode* next;
} *ucnode_t;

ucnode* listHead;  // 客戶端鏈表頭
ucnode* lp;    // 客戶端鏈表指針

#pragma endregion

#pragma region 依賴函數(shù)

// 鏈表插入數(shù)據(jù)
ucnode* insertNode(ucnode* head,SOCKET client, sockaddr_in addr, umsg msg) {
 ucnode* newNode = new ucnode();
 newNode->cInfo.client = client;
 newNode->cInfo.saddr = addr; 
 newNode->cInfo.msg = msg;
 ucnode* p = head;
 if (p == nullptr) {
  head = newNode;
 }
 else {
  while (p->next != nullptr) {
   p = p->next;
  }
  p->next = newNode;
 }
 return head;
}

// 鏈表刪除數(shù)據(jù)
ucnode* deleteNode(ucnode* head, SOCKET client) {
 ucnode* p = head;
 if (p == nullptr) {
  return head;
 }
 if (p->cInfo.client == client) {
  head = p->next;
  delete p;
  return head;
 }
 while (p->next != nullptr && p->next->cInfo.client != client) {
  p = p->next;
 }
 if (p->next == nullptr) {
  return head;
 }
 ucnode* deleteNode = p->next;
 p->next = deleteNode->next;
 delete deleteNode;
 return head;
}

// 接收客戶端消息(某個(gè))
void recvMessage(PVOID pParam) {
 clientInfo* cInfo = (clientInfo*)pParam;

 while (1) {
  // 接收來自客戶端的消息
  umsg msg;
  int len_client = sizeof(sockaddr);
  int ret_recv = recv(
   cInfo->client, // 本地套接字 
   (char*)&msg, // 存放接收的消息
   sizeof(msg), // 消息大小
   0    // 不修改函數(shù)調(diào)用行為
  ); 
  if (ret_recv <= 0) { cout << msg.name << "斷開連接: " << GetLastError() << endl; break; }
  cInfo->msg = msg;

  // sin_addr 轉(zhuǎn) char[](char[] 轉(zhuǎn) sin_addr 使用 inet_top)
  char arr_ip[20];
  inet_ntop(AF_INET, &cInfo->saddr.sin_addr, arr_ip, 16);

  // 處理消息(1:登錄,2:退出,3:會(huì)話)
  switch (cInfo->msg.type) {
  case 1:
   // 插入數(shù)據(jù)到鏈表
   insertNode(listHead,cInfo->client, cInfo->saddr,cInfo->msg);
   // 打印消息
   cout << "[" << arr_ip << ":" << ntohs(cInfo->saddr.sin_port) << "] " << msg.name << ":" << "---登錄---" << endl;
   break;
  case 2:
   // 從鏈表刪除數(shù)據(jù)
   deleteNode(listHead, /*cInfo->msg*/cInfo->client);
   // 打印消息
   cout << "[" << arr_ip << ":" << ntohs(cInfo->saddr.sin_port) << "] " << msg.name << ":" << "---退出---" << endl;
   break;
  case 3:
   // 打印消息
   cout << "[" << arr_ip << ":" << ntohs(cInfo->saddr.sin_port) << "] " << msg.name << ":" << cInfo->msg.text << endl;
   // 向其他客戶端廣播(除自己之外)
   lp = listHead;
   while (lp) {
    if (strcmp(lp->cInfo.msg.name, "") != 0 && strcmp(lp->cInfo.msg.name, cInfo->msg.name) != 0) {
     send(
      lp->cInfo.client,  // 本地套接字
      (char*)&cInfo->msg,  // 發(fā)送的消息
      sizeof(cInfo->msg),  // 消息大小
      0      // 不指定調(diào)用方式
     );
     int error_send = GetLastError();
     if (error_send != 0) { cout << "send failed:" << error_send << endl; }
    }
    lp = lp->next;
   }
   break;
  }
 }
}

#pragma endregion

int main()
{
 cout << "我是服務(wù)端" << endl;

 // 初始化 WSA ,激活 socket
 WSADATA wsaData;
 if (WSAStartup(
  MAKEWORD(2, 2),   // 規(guī)定 socket 版本為 2.2
  &wsaData    // 接收關(guān)于套接字的更多信息
 )) {
  cout << "WSAStartup failed : " << GetLastError() << endl;
 }

 // 初始化 socket、服務(wù)器信息
 server = socket(
  AF_INET,   // IPV4
  SOCK_STREAM, // TCP
  0    // 不指定協(xié)議
 );
 sai_server.sin_addr.S_un.S_addr = 0; // IP地址
 sai_server.sin_family = AF_INET;  // IPV4
 sai_server.sin_port = htons(8090);  // 傳輸協(xié)議端口

 // 本地地址關(guān)聯(lián)套接字
 if (bind(
  server,      // 要與本地地址綁定的套接字
  (sockaddr*)&sai_server,  // 用來接收客戶端消息的 sockaddr_in 結(jié)構(gòu)體指針
  sizeof(sai_server)
 )) {
  cout << "bind failed : " << GetLastError() << endl;
  WSACleanup();
 }

 // 套接字進(jìn)入監(jiān)聽狀態(tài)
 listen(
  server,  // 本地套接字
  SOMAXCONN // 掛起連接隊(duì)列的最大長度,SOMAXCONN:最大合理值
 );

 // 初始化客戶端鏈表
 listHead = new ucnode();
 listHead->next = nullptr;
 lp = listHead;
  
 // 接收消息
 while (1) {
  // 接收登錄消息(首次連接是觸發(fā),之后發(fā)送消息不觸發(fā))
  clientInfo* cInfo = new clientInfo();
  int len_client = sizeof(sockaddr);
  cInfo->client = accept(server, (sockaddr*) &cInfo->saddr, &len_client); 
  if (GetLastError() != 0) { continue; }
  
  // 接收登錄者的消息(每個(gè)客戶端對(duì)應(yīng)一個(gè)線程)
  HANDLE h_recvMes = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)recvMessage, cInfo, 0, 0);
  if (!h_recvMes) { cout << "CreateThread failed :" << GetLastError() << endl; }
 }

 // 禁用 socket
 WSACleanup();

 getchar();
    return 0;
}

客戶端代碼:

// Test_Console_2.cpp : 此文件包含 "main" 函數(shù)。程序執(zhí)行將在此處開始并結(jié)束。
//

#include 
#include 
#include 
#include 
#include 
#include 
#include 

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

using namespace std;

#pragma region 全局變量

SOCKET client;     // 本地套接字
sockaddr_in sai_client;   // 存放客戶端IP地址、端口

// 消息格式
struct umsg {
 int type;     // 協(xié)議(1:登錄,2:退出,3:發(fā)消息)
 char name[64];    // 用戶名字
 char text[512];    // 文本
};

#pragma endregion

#pragma region 依賴函數(shù)

// 監(jiān)聽服務(wù)器消息
void recvMessage()
{
 while (1){
  umsg msg;
  int ret_recv = recv(
   client,   // 本地套接字
   (char*)&msg, // 存放接收的消息
   sizeof(msg), // 消息大小
   0    // 不指定調(diào)用方式
  );
  if (ret_recv <= 0) { cout << "recv failed: " << GetLastError() << endl; break; }
  
  // 打印消息
  cout << msg.name << ": " << msg.text << endl;
 }
}

#pragma endregion

int main()
{
 cout << "我是客戶端" << endl;

 // 初始化 WSA ,激活 socket
 WSADATA wsaData;
 if (WSAStartup(
  MAKEWORD(2, 2),  // 規(guī)定 socket 版本
  &wsaData   // 接收 socket 的更多信息
 )) {
  cout << "WSAStartup failed : " << GetLastError() << endl;
 }

 // 初始化 socket、客戶端信息
 client = socket(
  AF_INET,  // IPV4
  SOCK_STREAM, // TCP
  0    // 不指定協(xié)議
 );
 sai_client.sin_family = AF_INET;         // IPV4
 inet_pton(AF_INET, "192.168.1.100", &sai_client.sin_addr);   // 服務(wù)器 IP地址
 sai_client.sin_port = htons(8090);         // 端口

 // 連接服務(wù)器
 int ret_connect = connect(
  client,      // 本地套接字
  (sockaddr*) &sai_client,  // 目標(biāo)
  sizeof(sai_client)
 );if (ret_connect != 0) { cout << "connect failed:" << GetLastError() << endl; }

 // 輸入用戶名
 umsg msg;
 msg.type = 1;
 string name;
 getline(cin, name);
 strncpy_s(msg.name, sizeof(msg.name), name.c_str(), 64);
 strncpy_s(msg.text, sizeof(msg.text), "", 512);

 // 發(fā)送登錄消息
 send(
  client,   // 本地套接字
  (char*)&msg, // 發(fā)送的消息
  sizeof(msg), // 消息大小
  0    // 不指定調(diào)用方式
 ); 
 int error_send = GetLastError();
 if (error_send != 0) { cout << "send failed:" << error_send << endl; }
 
 // 接收服務(wù)器消息
 HANDLE h_recvMes = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)recvMessage, 0, 0, 0);
 if (!h_recvMes) { cout << "CreateThread failed :" << GetLastError() << endl; }

 // 發(fā)送消息
 while (1) {
  string content;
  getline(cin, content);

  // 退出消息
  if (content == "quit") {
   msg.type = 2;
   send(
    client,   // 本地套接字
    (char*)&msg, // 發(fā)送的消息
    sizeof(msg), // 消息大小
    0    // 不指定調(diào)用方式
   );
   error_send = GetLastError();
   if (error_send != 0) { cout << "send failed:" << error_send << endl; }
   closesocket(client);
   WSACleanup();
   return 0;
  }
  
  // 會(huì)話消息
  msg.type = 3;
  strncpy_s(msg.text, sizeof(msg.text), content.c_str(), 512);
  send(
   client,   // 本體套接字
   (char*)&msg, // 發(fā)送的消息
   sizeof(msg), // 消息大小
   0    // 不指定調(diào)用方式
  );
  error_send = GetLastError();
  if (error_send != 0) { cout << "send failed:" << error_send << endl; }

 }

    getchar();
    return 0;
}

效果圖:

如何使用C++代碼實(shí)現(xiàn)多人聊天室

“如何使用C++代碼實(shí)現(xiàn)多人聊天室”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!


本文名稱:如何使用C++代碼實(shí)現(xiàn)多人聊天室
文章出自:http://weahome.cn/article/jdihgd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部