我自己记录的Socket笔记

2.网络技术    http://www.s8s8.net/index.php    junjianns    didadi    junjianns@yahoo.com.cn   
4.巨果操作系统    http://www.mlg.com.cn/bbs/index.asp    junjianns    didadi    junjianns@yahoo.com.cn

四. 网络通讯学习过程:
       1.在书中多线程界面的例子中,如何结束主线程中的界面,而主线程不结束,因为主线程一结束,所有线程都结束.
    2.文件映像笔记.在发送端和接收端的定义文件:
        typedef struct tagFileMappingStruct
        {
            int cou;
            TCHAR str[128];
        }FILEMAPPINGSTRUCT, *PFILEMAPPINGSTRUCT;
        PFILEMAPPINGSTRUCT m_pFileMappingStruct;
        HANDLE m_hFileMapping;
    在发送端和接收端的实现文件的初始化:
        m_hFileMapping=::CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,sizeof(FILEMAPPINGSTRUCT),"xh");
        m_pFileMappingStruct=(PFILEMAPPINGSTRUCT)::MapViewOfFile(m_hFileMapping,FILE_MAP_ALL_ACCESS,0,0,sizeof(FILEMAPPINGSTRUCT));
        m_pFileMappingStruct->cou=0;
    在发送端和接收端的实现文件的销毁中:
        ::UnmapViewOfFile(m_pFileMappingStruct);
        ::CloseHandle(m_hFileMapping);
    在发送代码中:
        TCHAR strTemp[128];
        GetDlgItemText(IDC_EDIT1,strTemp,sizeof(strTemp));
        if(strTemp==m_pFileMappingStruct->str)
            m_pFileMappingStruct->cou+=1;                //记录这个数据被写了几次.
        else
        {
            m_pFileMappingStruct->cou=1;
            strcpy(m_pFileMappingStruct->str,strTemp);
        }
    在接收代码中:
        TCHAR strTemp[128];
        GetDlgItemText(IDC_EDIT1,strTemp,sizeof(strTemp));
        if(strTemp==m_pFileMappingStruct->str)
            m_pFileMappingStruct->cou-=1;                //记录这个数据被读了几次.
        else
        {
            m_pFileMappingStruct->cou=-1;
            strcpy(strTemp,m_pFileMappingStruct->str);
        }
        SetDlgItemText(IDC_EDIT1,strTemp);
    3.WM_COPYDATA的应用.在发送代码中:
        CWnd* p = CWnd::FindWindow(NULL, TEXT("测试 WM_COPYDATA 消息:接收方"));
        COPYDATASTRUCT s;
        s.cbData = (text.GetLength() + 1) * sizeof(TCHAR);
        s.lpData = (LPVOID)LPCTSTR(text);
        p->SendMessage(WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM)&s);

    在接收端在响应WM_COPYDATA消息的代码中.
        LPCTSTR strText=(LPCTSTR)(pCopyDataStruct->lpData);        //收到了.


    4.用剪贴板.在定义文件中定义:
        typedef struct tagSelection
        {
            int startOff;    //    start offset for selection
            int endOff;        //    end offset for selection
        }SELECTION, *PSELECTION;
    在拷贝代码中:
        CString t;
        GetDlgItemText(IDC_TEXT, t);

        HGLOBAL h = ::GlobalAlloc(GMEM_MOVEABLE, sizeof(SELECTION));    //分配内存
        PSELECTION p = (PSELECTION)::GlobalLock(h);                        //锁定全局内存,返回指向内存块内容的第一个字节
        ((CEdit*)GetDlgItem(IDC_TEXT))->GetSel(p->startOff, p->endOff);    //为p->startOff,p->endOff赋值.
        ::GlobalUnlock(h);
       
        HGLOBAL hText = ::GlobalAlloc(GMEM_MOVEABLE,(t.GetLength() + 1) * sizeof(TCHAR));
        LPTSTR pText = (LPTSTR)::GlobalLock(hText);
        ::_tcscpy(pText, LPCTSTR(t));
        ::GlobalUnlock(hText);
       
        OpenClipboard();
        ::EmptyClipboard();
        ::SetClipboardData(CF_TEXT, hText);
        ::SetClipboardData(m_nSelectionFormat, h);
        ::CloseClipboard();
    在粘贴代码中:
        OpenClipboard();
        if (::IsClipboardFormatAvailable(CF_TEXT))
        {
            HGLOBAL h = (HGLOBAL)::GetClipboardData(CF_TEXT);
             LPCTSTR p = (LPCTSTR)::GlobalLock(h);
            SetDlgItemText(IDC_TEXT, p);
            ::GlobalUnlock(h);
             
             if (::IsClipboardFormatAvailable(m_nSelectionFormat))
            {
                HGLOBAL h = (HGLOBAL)::GetClipboardData(m_nSelectionFormat);
                 PSELECTION p = (PSELECTION)::GlobalLock(h);
                ((CEdit*)GetDlgItem(IDC_TEXT))->SetSel(p->startOff, p->endOff);
                ::GlobalUnlock(h);
             }
        }

        ::CloseClipboard();
    5.使用管道.形式类似于UDP,在接收端的定义文件定义:
        #define __PIPE_NAME__    TEXT("\\\\.\\pipe\\Message Pipe")
        #define STRINGSIZE    256
        HANDLE m_hPipe;
        OVERLAPPED m_o;
    在接收端的实现文件,创建命名管道.准备接收管道信息.   
        m_hPipe = NULL;
        ::memset(&m_o, 0, sizeof(OVERLAPPED));                        //必须初始化.

        m_hPipe=::CreateNamedPipe(__PIPE_NAME__, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,    1, STRINGSIZE, STRINGSIZE, 50, NULL);
        m_o.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        while (TRUE)
        {
            ::ConnectNamedPipe(m_hPipe, &m_o);                                    //等待接收一个命名管道的连接.立即返回
            while (::WaitForSingleObject(m_o.hEvent, 50) == WAIT_TIMEOUT)        //循环等待50毫秒.直到m_o.hEvent变为有信号量.
            {
                MSG msg;
                while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                    if (!::TranslateMessage(&msg))    ::DispatchMessage(&msg);
            }
            TCHAR buf[STRINGSIZE];
            DWORD fetched;
            ::ResetEvent(m_o.hEvent);                                    //有一个连接后把m_o.hEvent信号变为无信号状态.
            ::ReadFile(m_hPipe, buf, STRINGSIZE, &fetched, &m_o);        //读完后将m_o.hEvent信号变为有信号状态.       
            SetDlgItemText(IDC_MSG, buf);
            SetDlgItemText(IDC_MSG2, ::_tcsupr(buf));
            ::ResetEvent(m_o.hEvent);
            ::WriteFile(m_hPipe, buf, (::_tcslen(buf) + 1) * sizeof(TCHAR), &fetched, &m_o);    //写完后将m_o.hEvent信号变为有信号状态.       
            ::DisconnectNamedPipe(m_hPipe);
        }
    在发送端的实现文件中:   
        CString x;
        GetDlgItemText(IDC_MSG,x);
        ::CallNamedPipe(__PIPE_NAME__,(LPVOID)LPCTSTR(x),(x.GetLength()+1)*sizeof(TCHAR),buf,STRINGSIZE,&read,NMPWAIT_USE_DEFAULT_WAIT)
       
       
五. CChatServer程序分析.Socket中的多线程.
    1.CIniFile类,不如改用Serialize()省事,方便.
    2.Message结构.
    3.CMyTreeView类,
    4.CClientSocket
    5.CServerSocket
    6.CparseMessage    自定义消息处理中心.
    7.MFC中的Socket处理步骤:
    Server端,从CSocket派生类CServerSocket和CClientSocket,
        CServerSocket m_skServerSocket;    //声明部分定义.
         AfxSocketInit();
        m_skServerSocket.Create(port);
        m_skServerSocket.Listen();
        m_skServerSocket.Accept(CClientSocket);    //可以在CServerSocket中重写OnAccept用以控制把多线程中的CCriticalSection加锁.
        Receive(&Message,sizeof(Message));    //在CClientSocket类重写OnReceive,处理接收的信息后,把在CServerSocket中重写的OnAccept函数中的CCriticalSection解锁.
    Cient端,从CSocket派生类CMainSocket,
        CMainSocket m_skMainSocket;//声明部分定义.
        AfxSocketInit();
        m_skMainSocket.Create();
        m_skMainSocket.Connect(ServerIp,ServerPort)
        m_skMainSocket.Send(&Message,sizeof(Message));//发送数据
        Receive(&Message,sizeof(Message));//在CMainSocket中重写OnReceive,处理接收的信息.

    另外的学习:
    1.关于复制构造函数.在类的定义部分    public:CMyClass(const CMyClass & c);在类的实现部分对两个类中的成员变量进行赋值.
    2.关于CCriticalSection.我初步认为,要把它声明成全局的,在用的时候把它Lock(),用完后把它UnLock(),在Lock()和UnLock()
    中间的所有对象,变量在CPU执行的这段代码期间,其它线程不可同时访问这段代码中的对象,变量了.
    3.引用也即别名,也是取址.
    4.分析代码,先要弄清各变量的意义,以及变量在程序之间的联系.

 

 

一.函数:
    htonl:把主机字节顺序转换为网络字节顺序.转换的类型是u_long.用在SOCKADDR_IN::sin_addr::S_un::S_addr值中.
        该值存储的是u_long型的网络字节顺充的IP地址.
    htons:把主机字节顺序转换为网络字节顺序.转换的类型是u_short.用在SOCKADDR_IN::sin_port值中,
        该值存领教的是u_short型的网络字节顺序的端口号.
    inet_ntoa:把一个 in_addr 结构中的IPV4网络地址转换为字符串格式的点分IP地址.
    inet_addr
    
二.注意.
    1.在accept的时候,用
        int d=sizeof(ClientAddr);
        SOCKET accpSock=accept(s,(sockaddr*)&ClientAddr,&d );
    2.分配内存.
        CONNECTION_OBJ *newobj=NULL;            //CONNECTION_OBJ是一个自定义结构.
        // Allocate the object
        newobj = (CONNECTION_OBJ *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONNECTION_OBJ));
    3.
        在WaitForMultipleEvents函数中,网络事件触发了与一个套接字关联在一起的事件对象,工作状态便从未传信变成传信状态.
        在WaitForMultipleObjects函数中,监视一系列线程(用CreateThread创建)时是怎样将未传信变成传信状态的.
        解:当线程正在运行时是未传信状态.线程正常退出后是传信状态. See Synchronization Objects.

posted @ 2009-03-09 00:59  NewSea  阅读(509)  评论(0)    收藏  举报