大四中软实习笔记20130306

1 基于对话框的的TCP服务器建立步骤
1.1 建立基于对话框的MFC应用程序时,选支持Winsock
好处:我们不用再写加载/卸载 套接字库,以及头文件和lib文件了

1.2 设计界面------开启服务的按钮

1.3 关联 开启服务的成员函数

1.4 修改OnButtonOpenServer函数
注意点:
1 成员变量的使用
2 在Accept前面使用多线程--------因为是阻塞函数;但需求又必须执行Accept函数


知识点:
1 建立多线程
HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // pointer to security attributes   NULL
  DWORD dwStackSize,                         // initial thread stack size         0
  LPTHREAD_START_ROUTINE lpStartAddress,     // pointer to thread function        新的线程的入口函数
  LPVOID lpParameter,                        // argument for new thread            入口函数的参数---因为是地址,所以可以传进来很多参数
  DWORD dwCreationFlags,                     // creation flags                    0,则新的线程会马上进入 入口函数
  LPDWORD lpThreadId                         // pointer to receive thread ID    NULL,用来存新线程的ID号
);

2 入口函数的原型必须和下面一样
DWORD WINAPI ThreadProc(
  LPVOID lpParameter   // thread data
);
 
3 如何退出子线程
    CloseHandle(hThread);//其实不是关闭,而是让子线程的计数器减1。如果不加,相当于子线程永远不会退出,而发生内存泄露。
注意:它只是让计数器减一

4 怎样让图标成为 虚的
    GetDlgItem(IDC_BUTTON_OPEN_SERVER)->EnableWindow(FALSE);
    GetDlgItem(IDC_BUTTON_CLOSE_SERVER)->EnableWindow(TRUE);
注意:    GetDlgItem是成员函数;参数是图标的ID号;返回值是图标对应的对象的地址;
        EnableWindow也是(CWnd)成员函数,它的作用可以让图标变 虚
       
5 静态成员函数、静态成员变量
5.1 静态成员函数---外部函数 有相似的地方
相似:静态成员函数属于1个类,而不属于1个对象    
所以,静态成员函数的调用有2种方式:
方式一:跟普通成员函数一样
方式二:只要在函数名前加 类的作用域就可以
注意:静态成员函数 只能访问 静态成员变量
注意:
在.h中增加static


5.2 静态成员变量----全局变量 有相似的地方
相似:静态成员变量属于1个类,而不属于1个对象 
注意:
在.h中增加static
在.cpp中如此使用:
SOCKET CMfctcpserverDlg::socket_listen=NULL;
SOCKET CMfctcpserverDlg::socket_connect=NULL;
而且要放在函数的外面。

 

6 自定义消息

6.1 概念
BOOL PostMessage(
  HWND hWnd,      // handle of destination window  接收窗口的句柄-------任何窗口都有1个句柄
  UINT Msg,       // message to post                消息名称-----代表1大类消息
  WPARAM wParam,  // first message parameter        消息内容----如buf_recv数组中的数组名
  LPARAM lParam   // second message parameter       
);
知识点:
1 如何得到 主对话框的窗口句柄?
Dlg类里,天生就有,是基类的成员变量-----m_hWnd

可以通过CreateThread函数,传给入口函数ThreadProc
方法:利用如何函数的参数;注意要强制类型转换
代码如下:

void CMfctcpserverDlg::OnButtonOpenServer() 
{
    // TODO: Add your control notification handler code here

    socket_listen=socket(AF_INET,SOCK_STREAM,0);
    
    
    struct sockaddr_in addr_b;
    //addr_b.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); 
    addr_b.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
    addr_b.sin_port=htons(6588);
    addr_b.sin_family=AF_INET;
    struct sockaddr * addr=(struct sockaddr *)&addr_b;
    bind(socket_listen,addr,sizeof(SOCKADDR));
    
    int flag=listen(socket_listen,4);
    
    

    HANDLE hThread=CreateThread(NULL,0,ThreadProc,(LPVOID)m_hWnd,0,NULL);  //此处的m_hWnd是基类的成员变量,就是主对话框的 窗口句柄
    CloseHandle(hThread);//其实不是关闭,而是让子线程的计数器减1。如果不加,相当于子线程永远不会退出,而发生内存泄露。

    GetDlgItem(IDC_BUTTON_OPEN_SERVER)->EnableWindow(FALSE);
    GetDlgItem(IDC_BUTTON_CLOSE_SERVER)->EnableWindow(TRUE);    
}

DWORD WINAPI CMfctcpserverDlg ::ThreadProc(LPVOID lpParameter)
{
    //SOCKET socket_listen=(SOCKET)lpParameter;        //收到的lpParameter,其实是m_hWnd变量的复制品
    HWND hWnd1=(HWND)lpParameter;                    //通过强制类型转换,恢复了复制品的本来面目,即HWND类型
    sockaddr_in addr_bb;
    sockaddr * addr_client=(sockaddr *)&addr_bb;
    int len=sizeof(sockaddr);
    socket_connect=accept(socket_listen,addr_client,&len);
    
    
    char buf_recv[1000]={'\0'};
    int count=recv(socket_connect,buf_recv,sizeof(buf_recv)-1,0);
    //AfxMessageBox(buf_recv);
    //m_edit_show.Format("%s",buf_recv);
    //UpdateData(FALSE);
    ::PostMessage(m_hWnd1,DATA_USER,(WPARAM)buf_recv,NULL);
//    WPARAM a;
    
    return 0;
}

 

6.2 改进后的代码

//声明静态变量
     static SOCKET socket_listen;
     static SOCKET socket_connect;
    static DWORD WINAPI ThreadProc(  LPVOID lpParameter);

//在头文件中添加消息
afx_msg void OnRecvData(WPARAM wParam, LPARAM lParam);//add

//在cpp中添加函数声明
ON_MESSAGE(WM_RECV_DATA, OnRecvData) //cpp change

//实现函数体OnRecvData
void CMfctcpservertest1Dlg::OnRecvData(WPARAM wParam, LPARAM lParam)
{
    //AfxMessageBox("hello,zhangsan");
    char * recv_str = (char *)wParam;
    int d = strlen(recv_str);
    m_edit_show.Format("%d",d);
    UpdateData(FALSE);
    return;
}

//修改函数
DWORD WINAPI CMfctcpservertest1Dlg::ThreadProc(  LPVOID lpParameter)
{
    HWND hWnd1 = (HWND)lpParameter;
    
    sockaddr_in addr_bb;
    sockaddr * addr_client=(sockaddr *)&addr_bb;
    int len=sizeof(sockaddr);

    //SOCKET socket_listen = (SOCKET)lpParameter;
    socket_connect=accept(socket_listen,addr_client,&len);

    static char buf_recv[1000]={'\0'};

    int count =recv(socket_connect,buf_recv,sizeof(buf_recv)-1,0);
    
    //     m_edit_show.Format("%s",buf_recv);
    //     AfxMessageBox(buf_recv);
    ::PostMessage(hWnd1, WM_RECV_DATA, (WPARAM)buf_recv, NULL);
    //    WPARAM a;
    
    return 0;
}

void CMfctcpservertest1Dlg::OnButtonOpenserver() 
{
    // TODO: Add your control notification handler code here
    socket_listen=socket(AF_INET,SOCK_STREAM,0);
        
    struct sockaddr_in addr_b;
    addr_b.sin_addr.S_un.S_addr=htonl(INADDR_ANY); 
    addr_b.sin_port=6588;
    addr_b.sin_family=AF_INET;
    struct sockaddr * addr=(struct sockaddr *)&addr_b;
    bind(socket_listen,addr,sizeof(SOCKADDR));
    
    int flag = listen(socket_listen,4);

    HANDLE hThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)m_hWnd, 0, NULL);
    CloseHandle(hThread); //让子线程数目减1,如果不加,可能内存泄漏
    
    GetDlgItem(IDC_BUTTON_OPENSERVER)->EnableWindow(FALSE);
    GetDlgItem(IDC_BUTTON_CLOSESERVER)->EnableWindow(TRUE);
    
}

void CMfctcpservertest1Dlg::OnButtonCloseserver() 
{
    // TODO: Add your control notification handler code here
    closesocket(socket_connect);
    closesocket(socket_listen);

    GetDlgItem(IDC_BUTTON_OPENSERVER)->EnableWindow(TRUE);
    GetDlgItem(IDC_BUTTON_CLOSESERVER)->EnableWindow(FALSE);
    
}

posted on 2013-03-07 09:47  冰河程序猿  阅读(366)  评论(0编辑  收藏  举报

导航