基于MFC平台实现SOCKET通信

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_42034052/article/details/82628045

一、就先谈谈MFC

  MFC是Microsoft Foundation Classes的缩写,是由微软公司提供的一个类库,这是来帮助你完成图形界面的设计和软件平台的开发,但是不管是你软件的开发还是图形界面的设计都都不支持各位去用MFC,看了很多大牛博客都会教导你这个东西操作繁杂,而且不易入门,可以说当时选择在这个平台上做这个软件是一个错误。就我所了解的到现今更加倾向于Qt,也是各种大牛给我的最一致的软件。

二、实现通信我们就必须了解一下什么是SOCKET?

  Socket也成为套接字,套接字是支持TCP/IP网络通信的基本操作单元。多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口。

 

上面便是采用SOCKET实现通信的大致流程,当然计算机内部的实现肯不是这么简单,其中会涉及到TCP握手的建立连接和断开连接等等。

三、了解到了SOCKET就必须了解一下SOCKET通信的基本操作:

1.socket()函数

2.bind()函数

3.listrn()函数,connect()函数

4.accept()函数

5.read()函数、write()函数、receive()函数等

6.close()函数

7.TCP三次握手建立连接

8.TCP四次握手释放连接

3.1、socket()函数

socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket()描述符,它唯一标识一个socket.这个socket描述字跟文件描述字一样,后续操作都有用它来进行一些读写操作。

3.2、bind()函数

bind()函数是把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket.

3.3、listen()、connect()函数

如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这是调用connect()发出连接请求,服务器就会收到这个请求。

connect()函数则是用来发送连接请求的。

3.4、accept()函数

TCP服务器端依次调用socket()、bind()、listen()之后,就会监听制定的socket地址了。TCP客户端依次调用socket()、connect()之后就向TCP服务器发送了一个连接请求。TCP服务器监听这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作。

3.5、read()、write()、receive()等函数

当服务器与客户已经建立号连接之后就可以调用网络I/O进行读写操作了,即实现网络中不同进程之间的通信!网络I/O操作有下面几组:

read()/write()

recv()/send()

readv()/writev()

recvmsg()/sendmsg()

recvfrom()/sendto()

3.6、close()函数

在服务器与客户端建立连接后会进行一些读写操作,就要关闭相应的socket()描述字,好比操作完打开的文件要调用fclose关闭打开的文件

其中各种函数的具体参数的设置可以参考http://www.360doc.com/content/18/0902/22/38894361_783383225.shtml这位大牛的博客,关于socket通信的基本原理还是讲的较为清楚的。

3.7、TCP中三次握手建立连接详解:

1.客户方法端向服务器发送一个SYN J

2.服务器向客户端响应一个 SYN K,并对STN J进行确认ACK J+1

3.客户端再向服务端发送一个确认ACK K+1

(1) 服务器监听:服务器并不定位具体客户端的套接字,而是时刻处于监听状态;

(2) 客户端请求:客户端的套接字要描述它要连接的服务器的套接字,提供地址和端口号,然后向服务器套接字提出连接请求;

(3) 连接确认:当服务器套接字收到客户端套接字发来的请求后,就响应客户端套接字的请求,并建立一个新的线程,把服务器端的套接字的描述发给客户端。一旦客户端确认了此描述,就正式建立连接。而服务器套接字继续处于监听状态,继续接收其他客户端套接字的连接请求.

3.8、TCP中四次握手释放连接详解

1.某个应用进程首先调用close主动关闭连接,这时TCP发送一个 FIN M;

2.另一端接收到FIN M之后,执行被动关闭,对这个FIN 进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着该应用进程在这个相应的连接上再也接收不到其他额外的数据

3.一段时间之后,接收到文件结束符的应用进程会调用close()函数进行关闭socket操作,与此同时它的TCP也发送一个FIN N;

4.接收到这个FIN的源发送端的TCP会对它进行确认

四、具体的实现过程

1.图形界面的设计

2.客户端与服务端代码的写进

3.客户端与服务端之间能后实现信息的交互,最终实现局域网聊天

4.当然加入数据库后能实现更多的功能我也算是只是想实现聊天记录被实时送进数据库,然后返回出来被客户读取

5.最终构成了一个聊天软件

  在这个整体的实现过程中就主要是信息的交互,这是主要运用到了TCP/IP网络通信,然后就是MFC中按钮的设置,什么可以响应,什么时候无法响应,这些东西都只是运用到MFC中的函数就行,逻辑上面也没有什么难度。

  还有就是服务端开启和关闭,点击开启按钮如果已经开启则将其关闭,同时那个显示出来的按钮上信息也会改变,如果没有则开启服务端,然后就是客户端连接服务端,首先判断是否连接,如果连接上了就断开服务器,此后也会进行一系列的客户从服务端移除等等操作,如果没有此时状态判断是没有连接上的话就进行ip地址的读取和匹配,如果匹配成功则代表连接上同时更新聊天成员信息,如果没有匹配失败则显示连接失败信息,至于了客户端和服务端如何连接则是参考上面的3次握手建立TCP连接,断开同样参考上文四次握手释放连接。

  然后就是数据库的连接和数据入库了,首先会有一个数据库测试连接,我采用ODBC连接本地的MySQL数据库,测试连接成功是没有任何问题的,如果失败则会显示数据库连接失败,然后就是数据入库的问题,我的数据库只包含三个信息:1. 用户名 2. 发送的信息(str) 3.信息发送的时间(时间通过CTime来实现记录发送信息时的时间记录的),最后就是数据库中的数据读取,如果数据库中数据为空则不返回任何信息,如果有信息则按照上面的顺序依次将数据库中的信息打印出来,以便客户端的客户读取。

4.1、 图形界面设计

服务端图形界面:

// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO:  在此添加额外的初始化代码

    //----------------初始化------------------
    int n;
    CString noUser = _T("该用户不存在或者未上线");
    n = WideCharToMultiByte(CP_OEMCP, 0, noUser, -1, NULL, 0, 0, FALSE);
    m_strNoUser = new char[n];
    memset(m_strNoUser, 0, n*sizeof(char));
    WideCharToMultiByte(CP_OEMCP, 0, noUser.GetBuffer(0), n, m_strNoUser, n , 0, FALSE);
    m_users.AddString(_T("所有人"));
    m_connect = false;
    //设置“发送”按钮为不可用
    m_buttonSend.EnableWindow(FALSE);
    //----------------------------------------

void ClineDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

客户端图形界面:

// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO:  在此添加额外的初始化代码
    //------------------初始化---------------------
    SetDlgItemText(IDC_USERNAME,m_userName);
    //设置初始用户列表为只有一个,即“所有人”
    m_userslist.AddString(_T("所有人"));
    //设置“发送”按钮为不可用
    m_buttonSend.EnableWindow(FALSE);
    //设置“显示聊天记录”的按钮为不可用
    m_buttonShowHistory.EnableWindow(FALSE);

void ClineClientDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

4.2、客户端与服务端代码

服务端:

//启动/关闭服务器的服务
void ClineDlg::startServer()
{
    // TODO:  在此添加控件通知处理程序代码
    CString cport;
    //获取服务器的端口号
    GetDlgItemText(IDC_SERVERPORT,cport);
    //端口号的字符串转换为数字
    int port = _ttoi(cport);
    //如果没有填写端口号,则默认的端口号为1111
    if (port == 0)
    {
        m_port = 1111;
    }
    else
    {
        m_port = port;
    }
    //如果当前服务器的状态为开启,则关闭服务器
    if (m_connect)
    {
        //关闭服务器的socket
        delete m_listenSocket;
        m_listenSocket = NULL;
        m_connect = false;
        SetDlgItemText(IDC_BN_SERVER_START, _T("打开服务器"));
        UpdateEvent(_T("系统关闭服务器."));
        //关闭控件的只读状态
        m_editPort.SetReadOnly(FALSE);
        //设置“发送”按钮为不可用
        m_buttonSend.EnableWindow(FALSE);
        return;
    }
    //否则就打开服务器
    m_listenSocket = new CServerSocket();
    m_listenSocket->m_pDlg = this;
    m_listenSocket->m_userName = _T("服务器");
    // 指定对话框为主对话框,不能少了这句?
    UpdateData(true);
    // 创建服务器的套接字,IP地址默认本机IP
    if (!m_listenSocket->Create(m_port))
    {
        AfxMessageBox(_T("创建套接字错误!"));
        m_listenSocket->Close();
        return;
    }
    if (!m_listenSocket->Listen())
    {
        AfxMessageBox(_T("监听失败!"));
        m_listenSocket->Close();
        return;
    }
    m_connect = true;
    SetDlgItemText(IDC_BN_SERVER_START, _T("关闭服务器"));
    //更新聊天窗口中的消息
    UpdateEvent(_T("系统打开服务器."));
    //将服务器端口号的控件设置为只读状态
    if(port == 0)
    {
        m_editPort.SetWindowTextW(_T("1111"));
    }
    else 
    {
        m_editPort.SetWindowTextW(cport);
    }
    m_editPort.SetReadOnly(TRUE);
    //设置“发送”按钮为可用
    m_buttonSend.EnableWindow(TRUE);
}

//接收由客户端发来的消息
void ClineDlg::RecvData(CServerSocket* pSocket)
{
    char* pData = NULL;
    pData = new char[1024];
    memset(pData, 0, sizeof(char)* 1024);
    UCHAR leng = 0;
    CString str;
    if (pSocket->Receive(pData, 1024, 0) != SOCKET_ERROR)
    {
        str = pData;
        translateMsg(str, pSocket);
    }
    delete pData;
    pData = NULL;
}

//向服务器本身和所有客户端发送str消息
void ClineDlg::SendMSGToEvery(CString str)
{
    int n;
    //宽字节转多字节
    n = WideCharToMultiByte(CP_OEMCP, 0, str, -1, NULL, 0, 0, FALSE);
    char *pSend = new char[n];
    //初始化pSend
    memset(pSend, 0, n*sizeof(char));
    WideCharToMultiByte(CP_OEMCP, 0, str.GetBuffer(0), n, pSend, n , 0, FALSE);
    POSITION nPos = m_clientList.GetHeadPosition();
    while (nPos)
    {
        CServerSocket* pTemp = (CServerSocket*)m_clientList.GetNext(nPos);
        pTemp->Send(pSend, n);
    }
    delete pSend;
}


//移除已经退出连接的客户端
void ClineDlg::RemoveClient(CServerSocket* pSocket)
{
    POSITION nPos = m_clientList.GetHeadPosition();
    POSITION nTmpPos = nPos;
    //在客户端列表中查找该客户端
    while (nPos)
    {
        CServerSocket* pSockItem = (CServerSocket*)m_clientList.GetNext(nPos);
        //找到了就删除它
        if (pSockItem->m_hSocket == pSocket->m_hSocket)
        {
            CString userLeave;
            userLeave = pSockItem->m_userName;
            pSockItem->Close();
            delete pSockItem;
            int userIndex = m_users.FindString(0,userLeave);
            m_users.DeleteString(userIndex);
            m_clientList.RemoveAt(nTmpPos);
            m_userCount = m_clientList.GetCount();
            UpdateData(false);
            userLeave = _T("用户") + userLeave + _T("离开");
            UpdateEvent(userLeave);
            userLeave = _T("MUPDATEUSERLIST") + userLeave + _T("离开");
            //向服务器和所有客户端发送消息,更新服务器和所有客户端的聊天窗口内容
            SendMSGToEvery(userLeave);
            return;
        }
        nTmpPos = nPos;
    }

    CString userList = UPDATEUSERLIST;
    userList += translateUsersStr();
    //向服务器和所有客户端发送消息,更新服务器和所有客户端的聊天室内容
    SendMSGToEvery(userList);
}

//更新聊天窗口中的内容
void ClineDlg::UpdateEvent(CString str)
{
       CString string;
       // 获取系统当前时间
       CTime time = CTime::GetCurrentTime();
       // 用于换行显示日志
       str += _T("\r\n");
       // 格式化当前时间
       string = time.Format(_T("%Y/%m/%d %H:%M:%S  ")) + str;
       //获取编辑框最后一行索引
       int lastLine = m_event.LineIndex(m_event.GetLineCount() - 1);
       //选择编辑框最后一行
       m_event.SetSel(lastLine+1,lastLine+2,0);
       //替换所选那一行的内容
       m_event.ReplaceSel(string); 
}

//添加新的客户端
void ClineDlg::AddClient()
{
    CServerSocket *pSocket = new CServerSocket;
    pSocket->m_pDlg = this;
    m_listenSocket->Accept(*pSocket);
    pSocket->AsyncSelect(FD_READ | FD_WRITE | FD_CLOSE);
    m_clientList.AddTail(pSocket);
    m_userCount = m_clientList.GetCount();
    UpdateData(false);
}

//拆分字符串并根据字符串提示转发消息给所有客户端或者转发给指定的客户端
void ClineDlg::translateMsg(CString str, CServerSocket* pSocket)
{
    // 转发数据给所有用户,包括发送数据的用户
    CString cstr;
    int calls = str.Find(_T("MEVERY"));
    //获取具体的内容
    cstr = str.Right(str.GetLength() - calls - 6);
    //如果选中的是“所有人”,则给所有人发消息
    if (calls != -1)
    {
        //将socket中的userName和具体内容的字符串拼接起来(如userName是“服务器”,则就是“服务器对每个人说:xxxxx”)
        cstr = pSocket->m_userName + _T("对每个人说:") + cstr;
        SendMSGToEvery(cstr);
    }
    //否则就给指定客户端发消息
    else
    {
        //这里表示如果用户连接了服务器,将发送带有MUSERNAME的字符串消息
        int userName = str.Find(_T("MUSERNAME"));
        if (userName != -1)
        {
            cstr = str.Right(str.GetLength() - userName - 9);
            pSocket->m_userName = cstr;
            m_users.AddString(cstr);
            cstr = _T("用户")+cstr + _T("连接服务器");
            UpdateEvent(cstr);
            //给所有客户端包括服务器都发送某某某连接上了服务器的消息
            SendMSGToEvery(cstr);
            Sleep(1000);
            CString userList = UPDATEUSERLIST;
            userList += translateUsersStr();
            //更新服务器和所有客户端的聊天室列表
            SendMSGToEvery(userList);
        }
        else
        {
            int call = str.Find(_T("M"));
            cstr = str.Right(str.GetLength() - call -1);
            if (call != -1)
            {
                SendMSGToOne(cstr,pSocket->m_userName);
            }
        }
    }
}

//服务器发送消息给指定的一个客户端
void ClineDlg::SendMSGToOne(CString str,CString userSendName)
{
    CString userName;
    bool flag = false;
    CServerSocket* pTemp = NULL;
    CServerSocket* pSendUser = NULL;
    int cone = str.Find(_T(" "));
    userName = str.Left(cone);
    str = str.Right(str.GetLength() - cone);
    str = userSendName + _T("对你说:") + str;
    int n;
    //宽字节转多字节
    n = WideCharToMultiByte(CP_OEMCP, 0, str, -1, NULL, 0, 0, FALSE);
    char *pSend = new char[n];
    memset(pSend, 0, n*sizeof(char));
    //宽字节转多字节
    WideCharToMultiByte(CP_OEMCP, 0, str.GetBuffer(0), n, pSend, n , 0, FALSE);
    POSITION nPos = m_clientList.GetHeadPosition();
    //查找目标客户端
    while (nPos)
    {
        pTemp = (CServerSocket*)m_clientList.GetNext(nPos);
        //如果找到了目标客户端(接收方)
        if (userName == pTemp->m_userName)
        {
            flag = true;
            pTemp->Send(pSend, n);
        }
        //如果找到了发送方
        if (userSendName == pTemp->m_userName)
        {
            pSendUser = pTemp;
        }
    }
    //如果没有找到发送方,则默认是服务器给一个指定的客户端发送消息
    if (!flag)
    {
        pSendUser->Send(m_strNoUser, strlen(m_strNoUser));
    }
    delete pSend;
}

void ClineDlg::SendMSG()
{
    // TODO:  在此添加控件通知处理程序代码
    
    CString  msg;
    //获取消息框中的字符串
    GetDlgItemText(IDC_EDITMSG, msg);
    //获取当前选中的用户的下标(比如选中了某个人或者选中了“所有人”)
    int selectIndex = m_users.GetCurSel();
    if(selectIndex == -1)
    {
        MessageBox(_T("请在聊天室中选择发送对象!"));
        return ;
    }
    if(msg == _T(""))
    {
        MessageBox(_T("请输入要发送的内容!"));
        return ;
    }
    CString usermsg;
    //获取该下标的字符串名称
    m_users.GetText(selectIndex, usermsg);
    if (usermsg == "所有人")
    {
        usermsg = _T("MEVERY") + msg;
    }
    else
    {
        usermsg = _T("M") + usermsg + _T(" ") + msg;
    }
    translateMsg(usermsg, this->m_listenSocket);
}

客户端:

void ClineClientDlg::SendMsg()
{
    // TODO:  在此添加控件通知处理程序代码
    CString  msg;
    //获得消息框里的字符串
    GetDlgItemText(IDC_EDIT_MSG, msg);
    int selectIndex = m_userslist.GetCurSel();
    if(selectIndex == -1)
    {
        MessageBox(_T("请在聊天室中选择发送对象!"));
        return ;
    }
    if(msg == _T(""))
    {
        MessageBox(_T("请输入要发送的消息内容!"));
        return ;
    }
    CString usermsg;
    m_userslist.GetText(selectIndex, usermsg);

    if (usermsg == "所有人")

    {
        usermsg = _T("MEVERY") + msg;
    }
    else
    {
        usermsg = _T("M") + usermsg + _T(" ") + msg;
    }
    if (!usermsg.IsEmpty())
    {
        //未连接服务器则不执行
        if (!m_connect)
        {
            return;
        }
        UpdateData(true);
        GetDlgItemText(IDC_EDIT_MSG, m_DataSend);
        if (m_DataSend != "")
        {
            int n = 0;
            m_DataSend = usermsg;
            //通过将宽字节转换成多字节来获得多字节的位数
            n = WideCharToMultiByte(CP_OEMCP, 0, m_DataSend, -1, NULL, 0, 0, FALSE);
            char* pBuff = new char[n];
            //初始化数组
            memset(pBuff, 0, n);
            //将宽字节转换成多字节
            WideCharToMultiByte(CP_OEMCP, 0, m_DataSend.GetBuffer(0), n, pBuff, n, 0, FALSE);
            //发送消息
            m_pSock->SendMSG(pBuff, n);
        }
    }
}

//连接服务器
void ClineClientDlg::ConnectServer()
{
    // TODO:  在此添加控件通知处理程序代码
    GetDlgItemText(IDC_USERNAME, m_userName);
    //如果已经连接,则断开服务器
    if (m_connect)
    {
        //关闭并且删除客户端的socket
        m_connect = false;
        m_pSock->Close();
        delete m_pSock;
        m_pSock = NULL;
        m_ConPC.SetWindowTextW(_T("连接服务器"));
        m_buttonSend.EnableWindow(FALSE);
        m_buttonShowHistory.EnableWindow(FALSE);
        UpdateData(false);
        return;
    }
    //否则连接服务器
    else
    {
        //在这里创建新的socket
        m_pSock = new CClientSocket();
        //创建套接字
        if (!m_pSock->Create())
        {
            AfxMessageBox(_T("创建套接字失败!"));
            return;
        }
    }
    //获得ip控件的ip
    BYTE f1, f2, f3, f4;
    ((CIPAddressCtrl*)GetDlgItem(IDC_SERVERIPADDRESS))->GetAddress(f1, f2, f3, f4);
    m_strServerip.Format(_T("%d.%d.%d.%d"), f1, f2, f3, f4);
    m_port = GetDlgItemInt(IDC_SERVERPORT);
    //连接服务器
    if (!m_pSock->Connect(m_strServerip, m_port))
    {
        AfxMessageBox(_T("连接服务器失败!"));
        return;
    }
    else
    {
        m_connect = true;
        int n = 0;
        CString userName;
        userName = _T("MUSERNAME") + m_userName;
        //宽字节转多字节,确定要发送的字符串将占据多少个宽度的char
        n = WideCharToMultiByte(CP_OEMCP, 0, userName, -1, NULL, 0, 0, FALSE);
        char* pBuff = new char[n];
        memset(pBuff, 0, n);
        //宽字节转多字节,将要发送的字符串转化为字节流
        WideCharToMultiByte(CP_OEMCP, 0, userName.GetBuffer(0), n, pBuff, n, 0, FALSE);
        //通过socket发送多字节流连接
        m_pSock->SendMSG(pBuff, n);
        m_ConPC.SetWindowTextW(_T("断开服务器"));
        m_buttonSend.EnableWindow(TRUE);
        m_buttonShowHistory.EnableWindow(TRUE);
        UpdateData(false);
    }
}


//更新聊天室列表
void ClineClientDlg::UpdateUsers(CString str, int index)
{
    str = str.Right(str.GetLength()-strlen("MUPDATEUSERLIST"));
    CStringArray *strArray = translateUsersStr(str);
    int size = strArray->GetSize();
    m_userslist.ResetContent();
    m_userslist.AddString(_T("所有人"));
    for (int i = 0; i < size; i++)
    {
        m_userslist.AddString(strArray->GetAt(i));
    }
}

//通过“|”符号裁切字符串信息
CStringArray* ClineClientDlg::translateUsersStr(CString  str)
{
    CStringArray *strArray = new CStringArray;
    int length;
    CString *user=NULL;
    while (-1 != str.Find(_T("|") ))
    {
        //找到了一个“|”
        length = str.Find(_T("|"));
        user = new CString();
        //取“|”左边的字符串
        *user = str.Left(length);
        //更新字符串
        str = str.Right(str.GetLength() - length - 1);
        //更新数组
        strArray->Add(*user);
    }
    return strArray;
}


   我在客户端中定义发送消息的规则为发送消息之前将要发送消息的字符串进行打包(加首部),当消息传送到服务器端的时候服务器解包(去首部)就可以得到消息,还有包括图形界面的参数,文字规则的解读和发送都可以根据自己喜好更改。

4.3、客户端与服务端之间能后实现信息的交互,最终实现局域网聊天

4.4 数据库的连接

/测试连接数据库    

m_dataBase.Open(NULL,  false,  false, _T("ODBC;server=172.25.1.135;DSN=summer;UID=root;PWD=123456")  );     

if (!m_dataBase.IsOpen())     

{       

      AfxMessageBox(_T("DB open failed!"));       

      return false;     
}

数据库查询数据:

//查询数据库
    m_historyStr = _T("");

    CRecordset record(&m_dataBase); 
    int count = 0;  
        CString str2;  
        CString userNameFilter;
        //record.m_strFilter = _T("name='小白'");  
        userNameFilter.Format(_T("name='%s'"),m_userName);
        record.m_strFilter = userNameFilter;
        //my_record.m_strSort = _T("cust_id desc");  
        record.Open(CRecordset::snapshot  , _T("select * from history"));  
        record.MoveFirst();
        //如果数据库为空,则返回
        //int num = record.GetODBCFieldCount();
        if(record.IsBOF())  
        {  
            return ;  
        }  
        CDBVariant varValue;
  
        //获得表中全部数据
        while(!record.IsEOF())  
        {  
            record.GetFieldValue(2, str2);  
            m_historyStr += str2;
            m_historyStr +=_T("\r\n");
            record.GetFieldValue((short)0, str2);  
            m_historyStr += str2;
  
            record.GetFieldValue(1, str2);  
            m_historyStr += str2;
             
            m_historyStr +=_T("\r\n");
            record.MoveNext();  
            count++;  
        }  
    UpdateData(FALSE);
}

//每更改一次聊天窗口的内容,就更新数据库对应的聊天记录
void ClineClientDlg::updateDataBase(CString newStr)
{
    if(m_pSock == NULL)
    {
        return ;
    }
    //获取系统时间
    //SYSTEMTIME st;   
    //CString strDate,strTime;   
    //this->GetLocalTime(&st);   
    //strDate.Format("%4d-%2d-%2d",st.wYear,st.wMonth,st.wDay);   
    //strTime.Format("%2d:%2d:%2d",st.wHour,st.wMinute,st.wSecond);
    CTime curTime;
    curTime = CTime::GetCurrentTime();
    CString strCurTime;                 
    strCurTime.Format(_T("%4d-%2d-%2d %2d:%2d:%2d"), curTime.GetYear(),
    curTime.GetMonth(), curTime.GetDay(), curTime.GetHour(),
    curTime.GetMinute(), curTime.GetSecond());

    CString str;
    str.Format(_T("insert history value('%s','%s','%s')"),m_userName,newStr,strCurTime);
    m_dataBase.ExecuteSQL(str);
}

 

大致也就这样喽,个人比较菜,大牛看到错误望指出,让我加以更正!

 

 

展开阅读全文

没有更多推荐了,返回首页