程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> Netmsg局域網聊天程序

Netmsg局域網聊天程序

編輯:關於VC++

很早就想做一個類似QQ一樣的聊天程序,苦於一直沒有時間,再加上覺得網絡多點通信比較難做,所以這個想法就擱在一旁。最近二個月學校放假閒著無聊看了一些Tcp/ip,多線程的書,再加上以前的一點C++和VC的基礎,就著手做了起來,共化了17天完成了這個程序。它包括服務器端程序NetMsgServer和客戶端程序NetMsgClient。通過編程還發現原始的socket(像send,recv等)命令比VC封裝好的CScoket速度要快。怎麼說呢,程序不小,有3000多行的代碼,錯誤和垃圾代碼肯定也不少了,畢竟水平有限,大家看了不要扔雞蛋就謝謝了。

一、說明

本程序采用tcp/ip socket多線程編程,並對一些重要的同步操作做了超時控制,以減少等待的時間,像連接服務器,等待對方接收文件等。基本功能跟QQ類似,能進行多點的聊天和點對點的文件傳送。這種編程的優勢在於傳送的數據不會丟失,而且用戶上線下線能即時反應出來。唯一的遺憾是界面做的太濫,本人對界面編程一竅不通,暫且還只能在局域網內使用,因為沒有增加可以通過代理服務器的功能。

二、大概通信流程

1、NetMsgServer 服務器端

它采用了兩個線程,其中一個線程處理各個客戶端的連接請求(accept),另一個在客戶端請求連接成功後處理接收到的命令並返回信息,包括用戶注冊、登陸、下線、生成在線用戶列表、查詢修改某個在線用戶的信息等。

2、NetMsgClient客戶端

每個NetMsgClient客戶端既是信息服務器端,又是信息客戶端,所以能實現多點通信。

2.1

通過注冊來獲得用戶號碼。發送兩條命令:"REGT\t\n",再發送一個用戶資料的數據結構。注冊成功服務器返回一個id號給用戶,否則返回一個錯誤代碼。send(m_dcSocketClient,(char *)&userInf,sizeof(userInf),0);//發送用戶資料

其中:

USER_INF userInf;
//用戶信息的結構
typedef struct
{
  long id;
  char nickname[20];
  char sex[10];
  int age;
  char address[50];
  char password[20];
}USER_INF,*LPUSER_INF;
2.2

 

開啟第一個線程登陸服務器,端口是4000。以下1000表示我的id號,發送"USER 1000" 和"PASS password"命令要求登陸服務器。

2.3

如果登陸成功,就發送"LIST \t\n"命令到服務器端,取得在線用戶的列表,並顯示在列表框內。在線列表以結構數組的形勢傳送。recv(m_dcSocketClient,(char *)(m_onlineUser),sizeof(m_onlineUser),0);

其中:

ONLINEUSER_INF m_onlineUser[MAX_ONLINE_NUM]; //在線用戶數組
typedef struct
{
  long id;
  char nickname[20];
  char ip[16];
  SOCKET s;
}ONLINEUSER_INF,*LPONLINEUSER_INF;
2.4

 

然後開啟第二個線程創建消息服務器端,接受各個客戶端的連接請求,端口是4001。 while(TRUE)
{
  int sockLen=sizeof(inetAddr);
  if((sAccept=accept(sListen,(SOCKADDR*)&inetAddr,&sockLen))==INVA LID_SOCKET)
  {
    AfxMessageBox("錯誤:accept failed in threadMsg");
    return 1;
  }
  AfxBeginThread(threadRecvMsgServer,(LPVOID)sAccept);
}
2.5

如果接收到連接就開啟第三個線程接受對方的信息。recv(acceptSocket,buff,sizeof(buff),0)

假如我是1000這個用戶,接受到"chat 1001\t\n"指令,說明是1001這個用戶想和我聊天,如果我的聊天人數太多就拒絕1001的聊天請求。

sprintf(buff,"%d\t\n",REJECT_CHAT_REQ);send(acceptSocket,buff,sizeof(buff),0);

如果接受他的請求,就發送確認信息。

sprintf(buff,"%d\t\n",ACCEPT_CHAT_REQ);send(acceptSocket,buff,sizeof(buff),0);

接下來就可以通信了。

2.6

如果雙方還要求傳送文件,就開啟第4個線程,端口是4002,只是點對點的通信,如果1000想法送文件給1001,文件發送方建立文件服務器端,然後由消息通訊線路(即上面的acceptSocket)發送"File anc.avi\t\n"命令到對方消息通訊線路上,讓1001連接1000的file文件服務器。1001連接到1000的file服務器上後,發送確認命令決定是不是接收文件,如果接收就可以開始傳送文件。

2.7

假定我是1000這個用戶,1001已經連接到我的機器,並和我聊天,這時如果我還想和1002聊天,就開啟第5個線程發送"chat 1000\t\n"到1002的信息服務器端(端口4001,每個netmsg客戶端都有信息服務器端),如果還想和1003聊天,就開啟第6個線程發送命令"chat 1000\t\n"到1003的信息服務器端請求連接,這樣每個客戶端都可以實現多點通訊。

QQ:54476167

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved