MFC下CSocket 編程聊天室小項目

最近要做一個聊天室的網絡編程小項目,同事給我一份源碼,也能運行,但是有很多的bug,還有很多不太合理的地方。本來就想着把代碼看懂就行了,

可是有很多的內存泄露問題,於是決定自己動手寫一個。在寫的過程中,發現了一些問題,現在總結如下:

第一個問題:在使用MFC編寫socket編程時,必須包含<afxsock.h>頭文件

服務器端的主要過程:必須首先AfxSocketInit(), 接着creat一個端口,然後打開監聽端口listen, 然後等待接受客戶端的主動連接請求Accept

客戶端的主要過程:首先也是必須AfxSocketInit(),接着creat, 然後就可以請求連接了connect。


在服務器端必須同時定義兩個CSocket變量a、b,一個a用於creat和listen,另一個用於接受連接進行消息的接收和發送 a.Accept(b);



在類CAsyncSocket中,所有以On開頭的成員函數都是由框架自動調用的,不用自己單獨調用。在這個聊天室項目中,全局變量是CMysocket類型的,該類

繼承於CAsyncSocket類,其定義如下:

class CMysocket : public CAsyncSocket
{
public:
CMysocket();
virtual ~CMysocket();


void SetParent(CDialog *pWnd);
void OnClose(int nErrorCode);
void OnAccept(int nErrorCode);
void OnReceive(int nErrorCode);


private:
CDialog * m_pWnd;
};

在該類的成員函數的實現過程中,將接受客戶端的連接的函數指向了對話框的類的OnAccept函數

// CMysocket 成員函數
void CMysocket::OnAccept(int nErrorCode)
{

((CserverDlg *)m_pWnd)->OnAccept();
CAsyncSocket::OnAccept(nErrorCode);
}


在下面的函數的實現過程中,調用了類CAsyncSocket的成員函數Accept。從而完成了框架的自動完成服務器對客戶端的連接請求的接受,而不需要自己再對其接受連接的調用。同理,服務器端的接收字符和關閉也是如此實現的。

//成員函數, 接受連接
void CserverDlg::OnAccept()
{
//m_severSocket.Accept(m_connectSocket);
int i_ret;
i_ret = m_severSocket.Accept(m_connectSocket);
//AfxMessageBox(_T("AfxSocketInit 出錯誤"));
if(i_ret == SOCKET_ERROR)
{
CString m_ErrorMsg;
m_ErrorMsg = GetErrorMsg();
MessageBox(m_ErrorMsg);
return;

}


}


需要注意的問題:

1、在發送消息時,可能會出現只能發送一個字符的情況,根據發送函數send的返回值顯示正確發送字符串,但是客戶端只能接收一個字符

         解決方案:在客戶端和服務器端中同時做此操作。在項目中右鍵點擊“屬性”,在配置屬性->常規->字符  中選擇“使用多字節字符集”


2、在聊天室內容框控件Listbox Control中,會出現聊天信息的先後順序不和發送的順序一致

       解決方案:在該控件的屬性中,sort選擇 false

3、傳輸文件的時候,因爲文件大小的原因,所以通常的做法是文件分塊傳輸,同理接收文件的時候,也是分塊接收

在傳輸文件的時候,需要建立一個結構體,用來保存文件的相關信息,如文件的屬性、標題、大小和創建時間等。

typedef struct _SOCKET_STREAM_FILE_INFO {


    TCHAR       szFileTitle[128];                   //文件的標題名
    DWORD       dwFileAttributes;                   //文件的屬性
    FILETIME    ftCreationTime;                     //文件的創建時間
    FILETIME    ftLastAccessTime;                   //文件的最後訪問時間
    FILETIME    ftLastWriteTime;                    //文件的最後修改時間
    DWORD       nFileSizeHigh;                      //文件大小的高位雙字
    DWORD       nFileSizeLow;                       //文件大小的低位雙字
    DWORD       dwReserved0;                        //保留,爲0
    DWORD       dwReserved1;                        //保留,爲0


} SOCKET_STREAM_FILE_INFO, * PSOCKET_STREAM_FILE_INFO;

分塊發送文件:

recvSocket.Send(&StreamFileInfo,sizeof(SOCKET_STREAM_FILE_INFO));


UINT dwRead=0;


//分段發送文件內容
while(dwRead < StreamFileInfo.nFileSizeLow)
{
byte *data = new byte[1024];
UINT dw = myFile.Read(data, 1024);
recvSocket.Send(data, dw);
dwRead = dwRead + dw;
delete data;
}


接收文件的原理與此相同,分段接收。


4、內存問題

要注意內存泄露問題。包括接收消息時申請的緩衝區,要記得釋放,new與delete要配對存在

還有發送和接收文件的時候,申請的堆空間指針,要在每次用完的時候記得手動delete,以防內存泄露。



發佈了28 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章