三、具體實施
3.2 通信服務器
●多線程
每當服務器上有用戶連接成功,服務器都會為其創建兩個線程:接收線程(RecvData)和發送線程(SendData),並且接收線程在創建後處於可執行狀態,而發送線程則阻塞,等待服務器將其喚醒。這兩個線程都執行一個無限循環的過程,只有當通信出現異常或用戶端關閉連接時,線程才被自身所結束,並且,這兩個線程一定是同時生成,同時結束的。很顯然,每個連接產生兩個線程,使得數據轉發變的簡單,但同時又使得服務器的任務加重。因此,用戶端的連接數量有所限制,視服務器軟、硬件能力而定。
同時,由於多線程對結構體info_data都需要操作,所以線程間必須同步。這兒,我定義了互斥量CMutex m_mutex,用它的方法Lock()和Unlock()來完成同步。
我們首先來看一下接收線程(RecvData):(不完整代碼)
UINT RecvData(void* cs)
{
SOCKET clientSocket=(SOCKET)cs;
while(1)
{
numrcv=recv(clientSocket, buffer, MAXBUFLEN, NO_FLAGS_SET);
buffer[numrcv]=;
if(strcmp(buffer,"Close!")!=0) file://不是接收的“Close”數據
{
…………
for(i=0;i {
if(po!=NULL)
{
s1=s_info.GetNext(po);
if(s1.pet.Compare(petname)==0) file://比較昵稱是否一樣
{
m_mutex.Lock(); file://互鎖
info_data.data=pos;
info_data.thread=s1.thread;
m_mutex.Unlock(); file://解鎖
}
s1.thread->ResumeThread(); file://恢復發送相應的線程
break;
}
}
}
else
{
…………
if(clientSocket==s1.s_client)
{
m_mutex.Lock(); file://互鎖
info_data.data=buffer;
m_mutex.Unlock(); file://解鎖
s1.thread->ResumeThread(); file://恢復發送相應的線程
s_info.RemoveAt(po1); file://刪除該用戶信息
break;
}
………
goto aa;
}
}
aa: closesocketlink((LPVOID)clientSocket); file://關閉連接
AfxEndThread(0,true); file://結束本線程
return 1;
}
接下來看一下發送線程(SendData):(不完整代碼)
UINT SendData(void* cs)
{
SOCKET clientSocket=(SOCKET)cs;
while(1)
{
if(info_data.data!="Close!")
{
m_mutex.Lock(); file://互鎖
numsnd=send(clientSocket,info_data.data,
info_data.data.GetLength(),NO_FLAGS_SET); file://發送數據
now=info_data.thread;
m_mutex.Unlock(); file://解鎖
now->SuspendThread(); file://自身掛起
}
else
{ goto bb; }
}
bb: closesocketlink((LPVOID)clientSocket); file://關閉連接
AfxEndThread(0,true); file://結束本線程
return 1;
}
3.3 用戶端
很顯然,用戶端不用考慮多線程,網絡連接技術也比較成熟,因此在通信方面沒有什麼難題。但是,用戶端是面向實際用戶的,所以,不論是界面還是功能都必須友好。就像大多數軟件的更新一樣,界面友好度的提高以及功能的完善往往是放在首位的。由此可見,單從總體設計與技術實現角度來講,用戶端的工作量是十分大的,並且設計較服務器端復雜得 多。我粗略總結了以下幾條:
●與服務器通信格式兼容;
●操作簡單、易用,有美觀的界面及快捷鍵;
●准確地接收和傳輸數據;
●所有的數據記錄與提取功能;
●多種消息接收提示方式,比如托盤圖標(發送者頭像)閃爍、聲音提示等;
根據以上內容,我設計了三個獨立的對話框分別用來完成注冊、登陸、通信功能,登陸和注冊對話框與服務器的56789I/O端口連接,通信對話框與服務器的56790I/O端口連接,這樣就很好地實現了注冊登陸與通信的隔離,既能使服務器負載降低,同時又能保證一定的通信安全性。
由於本部分不是主要內容,詳細代碼見程序。
四、結束語
通過以上闡述可以知道,本系統分為服務器端和用戶端,服務器端又分為注冊/登陸服務器和通信服務器,通過通信服務器的轉發功能實現了局域網內的多用戶通信功能。本文運用了多線程技術和共享數據結構技術實現了通信服務器的轉發功能,使一般基於TCP/IP的網絡應用程序得到了發展。本系統已經在我實驗室的局域網(一台服務器,二十台客戶機)運行通過。
點擊 下載源代碼
參考文獻:
[1] Eugene Olafsen ,Kenn Scribner, K.David White等著. MFC Visual C++ 6.0編程技術內幕. 北京:機械工業出版社 2000.2
[2] Charles Wright. Visual C++程序員實用大全. 北京:中國水利水電出版社 2001.10
作者信息: 袁 淵(華東船舶工業學院 機械系,江蘇 鎮江 212003)