zoukankan      html  css  js  c++  java
  • windows 网络编程经典入门

    caiyi9000 原作

    转自: http://zhoumingbo.yeah.net

    对于一个windows网络编程初学者,下面方法是经典入门。 
    初学者建议不要用MFC提供的类,而用windows API做一个简单服务器和客户端,这样有助于对socket编程机制的理解。 
    为了简单起见,应用程序是基于MFC的标准对话框。 
    Winsock用WINDOWS API实现: 
    (1)服务器端有两个线程: 
    主线程 — 你需要编写以下函数来实现 

    #define NETWORK_EVENT USER_MESSAGE+100 //定义网络事件 
    sockaddr_in clientaddr; //暂时存放客户端IP地址 

    //自己定义消息映射函数,将上面定义的网络事件映射到处理函数 
    //OnNetEvent为网络事件处理函数,它在下面定义 
    ON_MESSAGE(NETWORK_EVENT, OnNetEvent); 

    在你对话框中的初始化函数中调用下面的初始化网络的子函数 
    BOOL InitNetwork() //初始化网络 

    //初始化TCP协议 
    BOOL ret = WSAStartup(MAKEWORD(2,2), &wsaData); 
    if(ret != 0) 

    MessageBox("初始化套接字失败!"); 
    return FALSE; 

    //创建服务器端套接字 
    SOCKET serverSocket 
    = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if(serverSocket == INVALID_SOCKET) 

    MessageBox("创建套接字失败!"); 
    closesocket(m_Socket); 
    WSACleanup(); 
    return FALSE; 

    //绑定到本地一个端口上 
    sockaddr_in localaddr; 
    localaddr.sin_family = AF_INET; 
    localaddr.sin_port = htons(1688); 
    localaddr.sin_addr.s_addr = 0; 
    if(bind(serverSocket ,(const struct sockaddr*)&localaddr, 
    sizeof(sockaddr)) == SOCKET_ERROR) 

    MessageBox("绑定地址失败!"); 
    closesocket(m_Socket); 
    WSACleanup(); 
    return FALSE; 

    //注册网络异步事件,m_hWnd为应用程序的主对话框或主窗口的句柄 
    WSAAsyncSelect(serverSocket, m_hWnd, NETWORK_EVENT, 
    FD_ACCEPT | FD_CLOSE | FD_READ | FD_WRITE); 

    listen(serverSocket, 5); //设置侦听模式 

    return TRUE; 

    //定义网络事件的响应函数 
    void OnNetEvent(WPARAM wParam, LPARAM lParam) 

    //调用API函数,得到网络事件类型 
    int iEvent = WSAGETSELECTEVENT(lParam); 

    //得到发出此事件的客户端套接字 
    SOCKET pSock = (SOCKET)wParam; 

    switch(iEvent) 

    case FD_ACCEPT: //客户端连接请求 

    OnAccept(); 

    break; 

    case FD_CLOSE: //客户端断开事件: 

    OnClose(pSock); 
    break; 

    case FD_READ: //网络数据包到达事件 

    OnReceive(pSock); 
    break; 

    case FD_WRITE: //发送网络数据事件 

    OnSend(pSock); 
    break; 

    default: break; 

    void OnAccept(SOCET pSock) //响应客户端连接请求函数 

    int len = sizeof(sockaddr); 

    //调用API函数,接受连接,并返回一个新套接字 
    //还可以获得客户端的IP地址 
    SOCKET clientSocket = accept(serverSocket, 
    (struct sockaddr*)&clientaddr, &len); 

    //为新的socket注册异步事件,注意没有Accept事件 
    if(WSAAsyncSelect(clientSocket ,m_hWnd, IP_EVENT, 
    FD_CLOSE | FD_READ | FD_WRITE) == SOCKET_ERROR) 

    MessageBox("注册异步事件失败!"); 
    return; 

    //自编函数,将此客户端的相关信息保存下来:套接字、 
    // IP地址、登陆时间 
    saveClientSocket(clientSocket,clientAddr,currentTimer); 

    void OnClose(SOCET pSock) 

    //自编函数,结束与相应的客户端的通信,释放相应资源并做相应处理 
    endClientSocket(pSock); 

    void OnSend(SOCET pSock) 

    //自编函数,在给客户端发数据时做一些预处理 
    handleOnSend(pSock); 

    void OnReceive(SOCET pSock) 

    recv(...); //调用API函数,读出网络缓冲区中的数据包 

    //自编函数,将此数据包和发出此数据的客户端 
    //clientSocket封装成一条网络消息 
    buildNetMsg(...); 

    //自编函数,将此网络消息放入一个消息队列中,由工作线程去处理 
    saveNetMsg(...); 
    SetEvent(...); //用事件对象触发工作线程 

    客户端登陆后,随即把自己的计算机名发给服务器,服务器接到后,把它保存下来。这样服务器就可以显示所有在线客户端的信息了,包括:客户端计算机名、IP地址、登陆时间等。 

    注意: 客户端没有OnAccept()函数,但有OnConnect()函数。 

    工作线程 — 
    在你的应用程序初始化时,创建并启动一个工作线程 

    AfxBeginThread(WorkThread,this,THREAD_PRIORITY_NORMAL); 
    //this可能为应用程序的主对话框或主窗口的句柄 

    UINT WorkThread(LPVOID pParam) 

    while(1) 

    //等待多重事件到来 
    int ret = WaitForMultipleObject(...); 

    switch(ret) 

    case OBJECT_0: 

    if(bNewNetMsg) //查看网络消息队列是否有新的网络消息 

    readNetMsg(...); //如有新的网络消息,则读出 
    handleNetMsg(...); //处理此网络消息 

    break; 

    case OBJECT_0 + 1: 

    //做退出处理 
    break; 

    default: break; 

    return 0; 
    }


    客户端为单线程,登陆服务器时,用connect()函数给服务器发连接请求; 
    客户端没有OnAccept()函数,但有OnConnect()函数。 
    在OnConnect()函数里做发连接请求时的预处理; 
    在OnReceive()函数里响应并处理网络数据; 
    在OnClose()函数里响应服务器的关闭事件; 
    在OnSend()函数里做发数据时的预处理; 

    如果你还想实现各客户端之间的在线交流(即所谓的聊天室),你在客户端还可以基于UDP协议 
    再做一套多点对多点的局域网组播模型模型,以后在和你聊,你先把上面的程序实现。 

    以上的I/O异步模型基于Windows的消息机制,另外还可以用事件模型、重叠模型或完成端口模型, 
    建议你参考Windows网络编程指南之类的书。 

    如果你能对上面的机制很熟练,你肯定已经对Winsock编网络程序的机制有一定理解,接下来你可以进行更精彩的编程, 不仅可以在网上传输普通数据,而且还 
    以传输语音、视频数据,你还可以自己做一个聊天室,和你的同学在实验室的局域网里可以共同分享你的成果。

  • 相关阅读:
    Python 存储引擎 数据类型 主键
    Python 数据库
    Python 线程池进程池 异步回调 协程 IO模型
    Python GIL锁 死锁 递归锁 event事件 信号量
    Python 进程间通信 线程
    Python 计算机发展史 多道技术 进程 守护进程 孤儿和僵尸进程 互斥锁
    Python 异常及处理 文件上传事例 UDP socketserver模块
    Python socket 粘包问题 报头
    Django基础,Day7
    Django基础,Day6
  • 原文地址:https://www.cnblogs.com/deltacat/p/3292594.html
Copyright © 2011-2022 走看看