MFC下CSocket 编程聊天室小项目

最近要做一个聊天室的网络编程小项目,同事给我一份源码,也能运行,但是有很多的bug,还有很多不太合理的地方。本来就想着把代码看懂就行了,

可是有很多的内存泄露问题,于是决定自己动手写一个。在写的过程中,发现了一些问题,现在总结如下:

第一个问题:在使用MFC编写socket编程时,必须包含头文件

服务器端的主要过程:必须首先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,以防内存泄露。



你可能感兴趣的:(MFC下CSocket 编程聊天室小项目)