windows上使用MFC窗口实现TCP/IP网络通信

最近项目中由于服务器端没有界面,所以需要实现网络通信来执行指令,这里简单记录一下。服务器端与客户端的搭建。

  1. 服务器端
    1.1 使用VS2019创建项目
    首先需要在VS2019中安装MFC的相关组件,通过visual studio installer即可快速安装。然后打开VS2019选择创建新项目->MFC应用,点击下一步。输入项目名称,选择项目存储位置,点击创建。注意这里将应用程序类型改为“基于对话框”,点击完成即可,如下图。
    选择MFC.png

    创建项目.png

    修改应用程序类型.png

    1.2 修改可视化界面
    打开“资源视图”里面的ServerMFCApp下面的rc文件,选择Dialog,双击打开IDD_SERVERMFCAPP_DIALOG。把里面的控件都删除掉,设置成自己的。如下图。
    UI.png

    然后双击Dialog中的启动按钮会自动生成事件处理方法,同样再点击发送按钮生成对应的处理方法。
    1.3 ServerMFCAppDlg.h

// ServerMFCAppDlg.h: 头文件
//

#pragma once
#include "pch.h"
#include <iostream>
// CServerMFCAppDlg 对话框
class CServerMFCAppDlg : public CDialogEx
{
// 构造
public:
    CServerMFCAppDlg(CWnd* pParent = nullptr);  // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_SERVERMFCAPP_DIALOG };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持


// 实现
protected:
    HICON m_hIcon;

    // 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()
public:
    SOCKET sock, ns;
    bool isRunning, socketConnected = false; //1.是否处于启动状态 2.判断是否有客户端连接
    bool init_network();//初始化并启动服务器
    afx_msg void OnBnClickedBtnStart();//点击启动按钮
    afx_msg void OnBnClickedBtnSend();//点击发送按钮
    void onHandleMsg(std::string msg);
    void sendMsg(char msg[]);
    void show_logs(CString msg);
    CListBox listLogs;
};

1.4 ServerMFCAppDlg.cpp

// ServerMFCAppDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "ServerMFCApp.h"
#include "afxdialogex.h"
#include "ServerMFCAppDlg.h"
#include "afxdialogex.h"
#define UM_SOCK WM_USER+100
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_ABOUTBOX };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CServerMFCAppDlg 对话框



CServerMFCAppDlg::CServerMFCAppDlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_SERVERMFCAPP_DIALOG, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CServerMFCAppDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST_LOG, listLogs);
    GetDlgItem(IDC_EDIT_PORT)->SetWindowText(CString("6543"));
}

BEGIN_MESSAGE_MAP(CServerMFCAppDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BTN_START, &CServerMFCAppDlg::OnBnClickedBtnStart)
    ON_BN_CLICKED(IDC_BTN_SEND, &CServerMFCAppDlg::OnBnClickedBtnSend)
END_MESSAGE_MAP()


// CServerMFCAppDlg 消息处理程序

BOOL CServerMFCAppDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != nullptr)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

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

    // TODO: 在此添加额外的初始化代码
    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
LRESULT CServerMFCAppDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    // TODO: Add your specialized code here and/or call the base class
    SOCKET s;
    int wmEvent;
    int len, remote_len;
    struct sockaddr_in remote;
    char text[30] = { };
    switch (message) {
    case UM_SOCK:
        s = (SOCKET)wParam;
        wmEvent = LOWORD(lParam);
        switch (wmEvent) {
        case FD_ACCEPT:
            show_logs(CString("已连接!"));
            len = sizeof(remote);
            ns = accept(s, (sockaddr*)&remote, &len);
            if (ns == SOCKET_ERROR) {
                this->socketConnected = false;
                closesocket(s);
                sock = 0;
                show_logs(CString("连接已关闭,请重启!"));
                break;
            }
            this->socketConnected = true;
            WSAAsyncSelect(ns, m_hWnd, UM_SOCK, FD_READ | FD_CLOSE);
            break;
        case FD_READ:
            len = recv(s, text, 30, 0);
            if (len <= 0) {
                break;
            }
            onHandleMsg(text);
            //MessageBox(cmd, _T(""), MB_OK);
            break;
        case FD_CLOSE:
            show_logs(CString("客户端断开连接!"));
            //MessageBox(_T("socket closed\n"), NULL, MB_OK);
            this->socketConnected = false;
            closesocket(ns);
            closesocket(s);
            break;
        default:
            break;
        }
        break;
    default:
        return CDialog::WindowProc(message, wParam, lParam);
    }
    return 0;
}
void CServerMFCAppDlg::onHandleMsg(std::string msg)
{
    //MessageBox(CString(msg.c_str()), _T(""), MB_OK);
    if (msg == "3") //拍照
    {
        show_logs(CString("收到客户端发来的信息:请求拍照!"));
        sendMsg("300");
    }
    else if (msg == "0")//打开相机
    {
        show_logs(CString("收到客户端发来的信息:请求打开相机!"));
        sendMsg("000");
    }
    else if (msg == "1")//关闭相机
    {
        show_logs(CString("收到客户端发来的信息:请求关闭相机!"));
        sendMsg("100");
    }
    else if (msg == "2")//录制视频
    {
        show_logs(CString("收到客户端发来的信息:请求录像!"));
        sendMsg("200");
    }
    else if (msg == "4")//录制视频
    {
        show_logs(CString("收到客户端发来的信息:请求停止录像!"));
        sendMsg("400");
    }
    else if (msg == "5")//检查相机是否已打开
    {
        sendMsg("000");
    }
    else//错误命令
    {
        sendMsg("500");
    }
}
bool CServerMFCAppDlg::init_network()
{
    WSADATA wsaData;

    //初始化TCP协议
    BOOL ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (ret != 0)
    {
        MessageBox(_T("初始化网络协议失败!"), _T("提示"));
        return false;
    }

    //创建服务器端套接字
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock == INVALID_SOCKET)
    {
        MessageBox(_T("创建套接字失败!"), _T("提示"));
        closesocket(sock);
        return false;
    }

    //绑定到本地一个端口上
    sockaddr_in localaddr;
    localaddr.sin_family = AF_INET;
    localaddr.sin_port = htons(6543);     //端口号不要与其他应用程序冲突
    localaddr.sin_addr.s_addr = 0;
    if (bind(sock, (struct sockaddr*) & localaddr, sizeof(sockaddr)) \
        == SOCKET_ERROR)
    {
        MessageBox(_T("绑定地址失败!"), _T("提示"));
        closesocket(sock);
        return false;
    }
    //将SeverSock设置为异步非阻塞模式,并为它注册各种网络异步事件,其中m_hWnd
    //为应用程序的主对话框或主窗口的句柄
    if (WSAAsyncSelect(sock, m_hWnd, UM_SOCK, FD_ACCEPT | FD_CLOSE | FD_READ | FD_WRITE) == SOCKET_ERROR)
    {
        MessageBox(_T("注册网络异步事件失败!"), _T("提示"));
        closesocket(sock);
        return false;
    }
    this->isRunning = true;
    listen(sock, 5);
    return true;
}
void CServerMFCAppDlg::sendMsg(char msg[])
{
    if (!this->isRunning)
    {
        show_logs(CString("服务器未启动!"));
        return;
    }
    if (!this->socketConnected)
    {
        show_logs(CString("没有客户端连接!"));
        return;
    }
    int strLen = send(ns, msg, sizeof(msg), 0);
    if (strLen == -1)
        show_logs(CString("未知错误,命令发送失败!"));
}
void CServerMFCAppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CServerMFCAppDlg::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();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CServerMFCAppDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}



void CServerMFCAppDlg::OnBnClickedBtnStart()
{
    // TODO: 在此添加控件通知处理程序代码
    if (this->isRunning) 
    {
        closesocket(sock);
    }
    else
    {
        show_logs(CString("正在启动服务器..."));
        if (init_network())
        {
            this->isRunning = true;
            SetDlgItemText(IDC_BTN_START, CString("停止"));
            show_logs(CString("服务器已启动...在6543端口监听"));
        }
        else
        {
            this->isRunning = false;
            SetDlgItemText(IDC_BTN_START, CString("启动"));
            show_logs(CString("服务器启动失败!请重试!"));
        }
    }
}
void CServerMFCAppDlg::show_logs(CString msg)
{
    listLogs.AddString(msg);
    listLogs.SetTopIndex(listLogs.GetCount() - 1);
}

void CStringToChar(CString str, char ch[])
{
    char* tmpch;
    int wLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
    tmpch = new char[wLen + 1];
    WideCharToMultiByte(CP_ACP, 0, str, -1, tmpch, wLen, NULL, NULL);
    for (int i = 0; i < wLen; ++i)
        ch[i] = tmpch[i];
}
void CServerMFCAppDlg::OnBnClickedBtnSend()
{
    // TODO: 在此添加控件通知处理程序代码
    CString msg;
    GetDlgItem(IDC_EDIT_MSG)->GetWindowText(msg);
    if (msg.GetLength() == 0) 
    {
        show_logs(CString("发送信息不能为空!"));
        return;
    }
    char chMsg[100];
    CStringToChar(msg, chMsg);
    show_logs(CString(chMsg));
    sendMsg(chMsg);
}


1.5 运行服务端
我这里的项目配置的是release以及x64的运行环境,点击本地windows调试器运行,报错如下。


运行报错.png

处理办法:在项目资源管理器中的项目名称上右键选择属性,将C/C++选项下的sdl检查调为否(最好是debug和release都调一下),如下图。


图片.png
  1. 客户端
    2.1 创建客户端项目
    参照前面客户端部分的创建,只是名字不同,我这里用的名字是ClientMFCApp。
    2.2 修改可视化界面


    客户端.png

    2.3 ClientMFCAppDlg.h

// ClientMFCAppDlg.h: 头文件
//

#pragma once
#include<iostream>

// CClientMFCAppDlg 对话框
class CClientMFCAppDlg : public CDialogEx
{
// 构造
public:
    CClientMFCAppDlg(CWnd* pParent = nullptr);  // 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_CLIENTMFCAPP_DIALOG };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持


// 实现
protected:
    HICON m_hIcon;

    // 生成的消息映射函数
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()
public:
    bool isConnect = false;
    bool isOpenCamera = false;
    bool isRecord = false;
    bool isRegRecvEvent = false;
    WSADATA wsaData;
    SOCKET hSocket;
    SOCKADDR_IN servAddr;
    afx_msg void OnBnClickedBtnCapture();
    afx_msg void OnBnClickedBtnConnect();
    afx_msg void OnBnClickedBtnOpenCap();
    afx_msg void OnBnClickedBtnRecVideo();
    void regRecvEvent();
    bool connect2Server();
    void handleRecvMsg(std::string text);
    bool sendMsg(char msg[]);
    void show_tips(CString msg);
    // 状态提示
    CListBox listTips;
};

2.4 ClientMFCAppDlg.cpp

// ClientMFCAppDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "ClientMFCApp.h"
#include "ClientMFCAppDlg.h"
#include "afxdialogex.h"
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<afxwin.h>
#include<iostream>
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
static UINT RecvEvent(LPVOID P);

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
CClientMFCAppDlg* pDlg;
class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_ABOUTBOX };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CClientMFCAppDlg 对话框



CClientMFCAppDlg::CClientMFCAppDlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_CLIENTMFCAPP_DIALOG, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CClientMFCAppDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST_TIPS, listTips);
    GetDlgItem(IDC_EDIT_IP)->SetWindowText(CString("127.0.0.1"));
    GetDlgItem(IDC_EDIT_PORT)->SetWindowText(CString("6543"));
}

BEGIN_MESSAGE_MAP(CClientMFCAppDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BTN_CAPTURE, &CClientMFCAppDlg::OnBnClickedBtnCapture)
    ON_BN_CLICKED(IDC_BTN_CONNECT, &CClientMFCAppDlg::OnBnClickedBtnConnect)
    ON_BN_CLICKED(IDC_BTN_OPEN_CAP, &CClientMFCAppDlg::OnBnClickedBtnOpenCap)
    ON_BN_CLICKED(IDC_BTN_REC_VIDEO, &CClientMFCAppDlg::OnBnClickedBtnRecVideo)
END_MESSAGE_MAP()


// CClientMFCAppDlg 消息处理程序

BOOL CClientMFCAppDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != nullptr)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

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

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

    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CClientMFCAppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CClientMFCAppDlg::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();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CClientMFCAppDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}
/*
    msg == "3" //拍照
    msg == "0" //打开相机
    msg == "1" //关闭相机
    msg == "2" //录制视频
*/
void CClientMFCAppDlg::OnBnClickedBtnCapture()
{
    // TODO: 在此添加控件通知处理程序代码
    if (this->isOpenCamera)
    {
        show_tips(CString("请求拍照中..."));
        sendMsg("3");
    }
    else
    {
        show_tips(CString("请先打开摄像头!"));
    }
}


void CClientMFCAppDlg::OnBnClickedBtnConnect()
{

    // TODO: 在此添加控件通知处理程序代码
    if (this->isConnect) 
    {
        this->isRegRecvEvent = false;
        this->isConnect = false;
        closesocket(hSocket);
        show_tips(CString("已断开连接!"));
        SetDlgItemText(IDC_BTN_CONNECT, CString("连接服务器"));
    }
    else 
    {
        if (connect2Server())
        {
            SetDlgItemText(IDC_BTN_CONNECT, CString("断开连接"));
        }
        else
        {
            SetDlgItemText(IDC_BTN_CONNECT, CString("连接服务器"));
        }
    }
    
}


void CClientMFCAppDlg::OnBnClickedBtnOpenCap()
{
    // TODO: 在此添加控件通知处理程序代码
    if (this->isOpenCamera)
    {
        show_tips(CString("正在请求关闭摄像头..."));
        sendMsg("1");
        Sleep(1000);
    }
    else
    {
        show_tips(CString("正在请求打开摄像头..."));
        sendMsg("0");
        Sleep(1000);
        
    }
}


void CClientMFCAppDlg::OnBnClickedBtnRecVideo()
{
    if (this->isOpenCamera)
    {
        if (isRecord)
        {
            show_tips(CString("正在请求结束视频录制..."));
            sendMsg("4");
        }else
        {
            show_tips(CString("正在请求录制视频..."));
            sendMsg("2");
        }
    }
    else
    {
        show_tips(CString("请先打开摄像头!"));
    }
}
void SplitCString(const CString& _cstr, const CString& _flag, CStringArray& _resultArray)
{
    CString strSrc(_cstr);

    CStringArray& strResult = _resultArray;
    CString strLeft = _T("");

    int nPos = strSrc.Find(_flag);
    while (0 <= nPos)
    {
        strLeft = strSrc.Left(nPos);
        if (!strLeft.IsEmpty())
        {
            strResult.Add(strLeft);
        }
        strSrc = strSrc.Right(strSrc.GetLength() - nPos - 1);
        nPos = strSrc.Find(_flag);
    }

    if (!strSrc.IsEmpty()) {
        strResult.Add(strSrc);
    }
}
bool CClientMFCAppDlg::connect2Server()
{
    int strLen;
    CString ip;
    CStringArray _resultArray;
    GetDlgItem(IDC_EDIT_IP)->GetWindowText(ip);
    SplitCString(ip, CString("."), _resultArray);
    if (_resultArray.GetSize() != 4)
    {
        show_tips(CString("主机地址输入有误!"));
        return false;
    }
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        show_tips(CString("WSA启动错误!"));
        return false;
    }

    hSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (hSocket == INVALID_SOCKET)
    {
        show_tips(CString("INVALID SOCKET!"));
        return false;
    }

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    InetPton(AF_INET, ip, &servAddr.sin_addr.s_addr);
    servAddr.sin_port = htons(6543);

    if (connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
    {
        show_tips(CString("连接服务器失败!"));
        return false;
    }
    this->isConnect = true;
    show_tips(CString("已连接到服务器,请打开摄像头!"));
    regRecvEvent();
    sendMsg("5");
    return true;
}
void CClientMFCAppDlg::show_tips(CString msg)
{
    listTips.AddString(msg);
    listTips.SetTopIndex(listTips.GetCount() - 1);
}
bool CClientMFCAppDlg::sendMsg(char msg[])
{
    if (!isConnect)
    {
        show_tips(CString("未连接到服务器!"));
        return false;
    }
    int strLen = send(hSocket, msg, sizeof(msg), 0);
    if (strLen == -1)
        show_tips(CString("未知错误,命令发送失败!"));
}
void CClientMFCAppDlg::regRecvEvent()
{
    this->isRegRecvEvent = true;
    CWinThread* thread = AfxBeginThread(RecvEvent, this, THREAD_PRIORITY_NORMAL, 0, 0, NULL);//返回线程句柄
}
/*
    msg == "0" //打开相机 000 打开摄像头成功 001 打开摄像头失败
    msg == "1" //关闭相机 100 关闭摄像头成功
    msg == "2" //录制视频 200 开始录制视频
    msg == "3" //拍照     300 拍照成功
    msg == "4" //停止录制 400 录制视频完成
*/
void CClientMFCAppDlg::handleRecvMsg(string text)
{   
    //MessageBox(CString(text.c_str()), _T("1"));
    CString tmp("收到服务器发来的信息:");
    tmp.Append(CString(text.c_str()));
    show_tips(tmp);
    if (text == "000")
    {
        this->isOpenCamera = true;
        show_tips(CString("摄像头已打开!"));
        SetDlgItemText(IDC_BTN_OPEN_CAP, CString("关闭摄像头"));
    }
    else if (text == "001")
    {
        this->isOpenCamera = false;
        show_tips(CString("摄像头处于关闭状态!"));
        SetDlgItemText(IDC_BTN_OPEN_CAP, CString("打开摄像头"));
    }
    else if (text == "100")
    {
        this->isOpenCamera = false;
        show_tips(CString("摄像头已关闭!"));
        SetDlgItemText(IDC_BTN_OPEN_CAP, CString("打开摄像头"));
    }
    else if (text == "200")
    {
        this->isRecord = true;
        show_tips(CString("开始录制视频!"));
        SetDlgItemText(IDC_BTN_REC_VIDEO, CString("结束录制"));
    }
    else if (text == "300")
    {
        show_tips(CString("拍照完成!"));
    }
    else if (text == "400")
    {
        this->isRecord = false;
        show_tips(CString("视频录制完成!"));
        SetDlgItemText(IDC_BTN_REC_VIDEO, CString("录制视频"));
    }
}
UINT RecvEvent(LPVOID p)
{
    int len = 0;
    char text[30] = { };
    pDlg = (CClientMFCAppDlg*)p;
    while (pDlg->isRegRecvEvent)
    {
        len = recv(pDlg->hSocket, text, 30, 0);
        if (len <= 0) {
            continue;
        }
        pDlg->handleRecvMsg(text);
    }
    return 0LU;
}
  1. 最终运行结果如下图
    运行截图.png

    ——————————————————————————————————————————————————————
    Gitee地址:服务器端 客户端
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351