//基於重疊i/0模型的簡單的回顯tcp伺服器,它接受客戶端連線之後,將從客
//戶端接收到的資料再傳送給客戶端。本例採用了單執行緒。
//使用重疊i/o模型必須使用wsasocket函式建立套接字,傳送資料使用
//wsasend、wsarecv、wsarecvfrom
//wsasocket函式建立套接字,這個套接字允許多個i/o同時占用。並使用pbuff
//er->psocket->noutstandingops來統計其上的i/o數量。
//其中socket_obj結構用來記錄與套接字相關的資訊,buffer_obj記錄i/o資訊。
//程式每投遞乙個i/o請求,都要申請乙個buffer_obj物件,使用嵌在物件中
//表,表頭指標為全域性變數g_pbufferhead。
//提交重疊i/o是重疊模型的關鍵,通過呼叫acceptex、wsarecv和wsasend函
//數實現。提交這些i/o後,執行緒便在重疊結構中的事件物件上等等,一旦i/o完成
//事件受信,等待函式返回。
//wsagetlasterror函式報告了wsa_io_pending出錯狀態,表示i/o操作正在進行。
//accepex函式將幾個套接字函式的功能集合成在了一起。如果它投遞的請求成功完成,則執行了3個操作:
//1、接受了新的連線
//2、新連線的本地位址和遠端位址都會返回
//3、接收到了遠端主機發來的第一塊資料 //
#include "../common/initsock.h"
#include
#include
#include
cinitsock thesock;
#define buffer_size 1024
typedef struct _socket_obj
socket_obj, *psocket_obj;
//重疊i/o都要提交到特定套節字上。在這些i/o完成之前,對方關閉了連線,
//或者連線發生錯誤,釋放對應的soceket_obj物件。
intnoperation;//提交的操作型別
#define op_accept1
#define op_read2
#define op_write3
socketsaccept;//用來儲存acceptex接受的客戶套節字(僅對監聽套節字而言)
_buffer_obj *pnext;
} buffer_obj, *pbuffer_obj;
handleg_events[wsa_maximum_wait_events];//i/o事件控制代碼陣列
intg_nbuffercount;//上陣列中有效控制代碼數量
pbuffer_obj g_pbufferhead, g_pbuffertail;//記錄緩衝區物件組成的表的位址
// 申請套節字物件和釋放套節字物件的函式
psocket_obj getsocketobj(socket s)
return psocket;
}void freesocketobj(psocket_obj psocket)
pbuffer_obj getbufferobj(psocket_obj psocket,ulong nlen)
else
g_events[++ g_nbuffercount] =pbuffer->ol.hevent;
}return pbuffer;
}void freebufferobj(pbuffer_obj pbuffer)
else
}// 釋放它占用的記憶體空間
if(bfind)
}pbuffer_obj findbufferobj(handle hevent)
return pbuffer;
}void rebuildarray()
}bool postaccept(pbuffer_obj pbuffer)
return true;
}bool postsend(pbuffer_obj pbuffer)
return true;
}bool handleio(pbuffer_obj pbuffer)
// 沒有錯誤發生,處理已完成的i/o
switch(pbuffer->noperation)
rebuildarray();
//將資料複製到傳送緩衝區
psend->nlen= dwtrans;
memcpy(psend->buff,pbuffer->buff, dwtrans);
//投遞此傳送i/o(將資料回顯給客戶)
if(!postsend(psend))
//繼續投遞接受i/o
postaccept(pbuffer);
}break;
case op_read:// 接收資料完成
else//套節字關閉
if(psocket->noutstandingops== 0)
freesocketobj(psocket);
freebufferobj(pbuffer);
returnfalse;}}
break;
caseop_write:// 傳送資料完成
else//套節字關閉
if(psocket->noutstandingops== 0)
freesocketobj(psocket);
freebufferobj(pbuffer);
returnfalse;}}
break;
}return true;
}//plisten可被多個重疊i/o占用
sockaddr_insi;
si.sin_family = af_inet;
si.sin_port = ::ntohs(nport);
si.sin_addr.s_un.s_addr = inaddr_any;
::bind(slisten, (sockaddr*)&si,sizeof(si));
::listen(slisten, 200);
// 為監聽套節字建立乙個socket_obj物件
psocket_obj plisten = getsocketobj(slisten);
// 載入擴充套件函式acceptex
guid guidacceptex = wsaid_acceptex;
dword dwbytes;
wsaioctl(plisten->s,
sio_get_extension_function_pointer,
&guidacceptex,
sizeof(guidacceptex),
&plisten->lpfnacceptex,
sizeof(plisten->lpfnacceptex),
&dwbytes,
null,
null);
// 建立用來重新建立g_events陣列的事件物件
g_events[0] = ::wsacreateevent();
// 在此可以投遞多個接受i/o請求
for(int i=0; i<5; i++)
::wsasetevent(g_events[0]);
while(true)
nindex = nindex -wsa_wait_event_0;
for(int i=0;i<=nindex; i++)
//處理這個i/o
pbuffer_objpbuffer = findbufferobj(g_events[i]);
if(pbuffer!= null)}}
}}
網路程式設計 客戶 伺服器程式設計正規化
迭代tcp伺服器總是在完全處理某個客戶的請求之後才開始下乙個客戶的請求處理。這樣的伺服器實際中比較少見。基於udp的大多伺服器卻是這樣實現。傳統併發伺服器呼叫fork派生乙個子程序來處理每個客戶,這使得伺服器能夠同時為多個客戶服務,每個程序乙個客戶。客戶數目的唯一限制是作業系統對其能夠同時擁有多少子...
Linux網路程式設計 伺服器模型
學習過 軟體工程 吧.軟體工程可是每乙個程式 員 必修 的課程啊.如果你沒有學習過,建議你去看一看.在這一章裡面,我們一起來從軟體工程的角度學習網路程式設計的思想.在我們寫程式之前,我們都 應該從軟體工程的角度規劃好我們的軟體,這樣我們開發軟體的效率才會高.在網路程式裡面,一般的來說都是許多客戶機對...
伺服器TCP網路程式設計實踐
這個問題涉及到2個tcp連線狀態,close wait與time wait。我想描述清楚這2個狀態,將會對伺服器關閉的生命週期了解的更為清晰。1 定義 假設有伺服器a正在執行,接受從客戶端c傳送過來的連線。在某個時間點上,c正常關閉了連線 一般正常關閉是使用close函式 此時伺服器在recv函式上...