Windows网络编程

Windows网络编程

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

第一章 序言



 

              我写这个专题的目的,一方面是为了通过对网络编程再一次系统的总结,提高自己的网络编程水平,特别是Windows下的网络编程水平。同一时候,我也希望,能为众多初学网络编程的人提供一点帮助,由于我開始学习网络编程的时候,能找到的资料就非常少。当然,花钱能够买到翻译版本号的书:)

              首先向大家推荐一本非常好的參考书,Network Programming for Microsoft Windows 2nd

初学网络编程的时候我还不知道有这样一本好书,仅仅是上各大论坛把能找到的网络编程方面的文章和代码下载下来,然后自己研究。后来看到别人推荐这一本书,下载了一个,看了感觉非常好,里面的内容写得非常规范,条理也非常清楚,英文好的朋友能够直接阅读,不然就仅仅好去弄一本翻译好的来研究了。、

              我试着从Windows编程的基础開始,一直到探索建立高性能的网络应用程序。我说过,我并非以高手的身份写这本书,而是以和大家一起学习的心态学习网络编程,写书仅仅是让自己的思路更清晰,以后还能够翻阅。所以,我不保证书中全部的内容都是绝对正确和标准的,有不妥的地方,还希望高手批评指正。

              这本书是全然免费的,读者能够随意使用书中的代码。可是假设须要转载,请注明原作者和出处。假设有商业运作的需求,请直接和我联系。



 



 

第二章 Windows网络编程基础



 

              这本书主要探索Windows网络编程,开发平台是Windows 2000 Visual C++.NET,从一个合格的C++程序猿到网络编程高手,还是须要花不少功夫,至少我觉得写一个聊天程序非常easy,而要写一个能同一时候响应成千上万用户的高性能网络程序,的确不容易。这篇文章所介绍的方法也并非能直接应用于每个详细的应用程序,仅仅能作为学习的參考资料。

              开发高性能网络游戏恐怕是促使非常多程序猿研究网络编程的原因(包含我),如今的大型网络游戏对同一时候在线人数的要求比較高,真正的项目往往採取多个server(组)负荷分担的方式工作,我将首先把注意力放到单个server的情况。

              大家都知道,我们用得最多的协议是UDPTCPUDP是不可靠传输服务,TCP是可靠传输服务。UDP就像点对点的传输数据一样,发送者把数据打包,包上有收信者的地址和其它必要信息,至于收信者能不能收到,UDP协议并不保证。而TCP协议就像(实际他们是一个层次的网络协议)是建立在UDP的基础上,添�了校验和重传等复杂的机制来保证数据可靠的传达到收信者。关于网络协议的详细内容,读者能够參考专门介绍网络协议的书籍,或者查看RFC中的有关内容。本书直接探讨编程实现网络程序的问题。

             



 



 

21 Window Socket介绍



 

              Windows Socket是从UNIX Socket继承发展而来,最新的版本号是2.2。进行Windows网络编程,你须要在你的程序中包括WINSOCK2.HMSWSOCK.H,同一时候你须要加入�引入库WS2_32. LIBWSOCK32.LIB。准备好后,你就能够着手建立你的第一个网络程序了。

              Socket编程有堵塞和非堵塞两种,在操作系统I/O实现时又有几种模型,包含SelectWSAAsyncSelectWSAEventSelect IO重叠模型,完毕port等。要学习主要的网络编程概念,能够选择从堵塞模式開始,而要开发真正有用的程序,就要进行非堵塞模式的编程(非常难想象一个大型server採用堵塞模式进行网络通信)。在选择I/O模型时,我建议刚開始学习的人能够从WSAAsyncSelect模型開始,由于它比較简单,并且有一定的有用性。可是,差点儿全部人都认识到,要开发同一时候响应成千上万用户的网络程序,完毕port模型是最好的选择。

              既然完毕port模型是最好的选择,那为什么我们不直接写出一个使用完毕port的程序,然后大家稍加改动就OK了。我觉得这确实是一个好的想法,可是真正做项目的时候,不同的情况对程序有不同的要求,假设不深入学习网络编程的各方面知识,是不可能写出符合要求的程序,在学习网络编程曾经,我建议读者先学习一下网络协议。



 



 



 

22 第一个网络程序



 

因为server/client模式的网络应用比較多,并且server端的设计是重点和难点。所以我想首先探讨server的设计方法,在完毕server的设计后再探讨其它模式的网络程序。

设计一个主要的网络server有下面几个步骤:

1、初始化Windows Socket

2、创建一个监听的Socket

3、设置server地址信息,并将监听port绑定到这个地址上

4、開始监听

5、接受client连接

6、和client通信

7、结束服务并清理Windows Socket和相关数据,或者返回第4



 

              我们能够看出设计一个最简单的server并不须要太多的代码,它全然能够做一个小型的聊天程序,或进行数据的传输。可是这仅仅是我们的開始,我们的终于目的是建立一个有大规模响应能力的网络server。假设读者对操作系统部分的线程使用还有疑问,我建议你如今就開始复习,由于我们常常使用线程来提高程序性能,事实上线程就是让CPU不停的工作,而不是总在等待I/O,或者是一个CPI,累死了还是一个CPU。千万不要以为线程越多的server,它的性能就越好,线程的切换也是须要消耗时间的,对于I/O等待少的程序,线程越多性能反而越低。

              以下是简单的server和client源码。(堵塞模式下的,供刚開始学习的人理解)



 



 

TCPServer



 

#include <winsock2.h> 
    

   
    
      
   
void main(void) 
    
{ 
    
   WSADATA              wsaData; 
    
   SOCKET               ListeningSocket; 
    
   SOCKET               NewConnection; 
    
   SOCKADDR_IN          ServerAddr; 
    
   SOCKADDR_IN          ClientAddr; 
    
   int                  Port = 5150; 
    
    
    
   // 初始化Windows Socket 2.2 
    
   WSAStartup(MAKEWORD(2,2), &wsaData); 
    
    
    
   // 创建一个新的Socket来响应client的连接请求 
    
   ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    
    
    
   // 填写server地址信息 
    
   // port为5150 
    
   // IP地址为INADDR_ANY,注意使用htonlIP地址转换为网络格式 
    
   ServerAddr.sin_family = AF_INET; 
    
   ServerAddr.sin_port = htons(Port);     
    
   ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    
           
    
   // 绑定监听port 
    
   bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)); 
    

   
    
      
   
   // 開始监听,指定最大同一时候连接数为5 
    
      listen(ListeningSocket, 5); 
    

   
    
      
   
   // 接受新的连接 
    
   NewConnection = accept(ListeningSocket, (SOCKADDR *) &ClientAddr,&ClientAddrLen)); 
    

   
    
      
   
   // 新的连接建立后,就能够互相通信了,在这个简单的样例中,我们直接关闭连接, 
    
   // 并关闭监听Socket,然后退出应用程序 
    
   //   
    
      closesocket(NewConnection); 
    
      closesocket(ListeningSocket); 
    

   
    
      
   
   // 释放Windows Socket DLL的相关资源 
    
      WSACleanup(); 
    
} 
    



 



 

TCPClient



 

# include <winsock2.h> 
    

   
    
      
   
void main(void) 
    
{ 
    
   WSADATA              wsaData; 
    
   SOCKET               s; 
    
   SOCKADDR_IN          ServerAddr; 
    
   int                  Port = 5150; 
    
    
    
   //初始化Windows Socket 2.2 
    
   WSAStartup(MAKEWORD(2,2), &wsaData); 
    
    
    
   // 创建一个新的Socket来连接server 
    
      s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    
    
    
   // 填写client地址信息 
    
   // port为5150 
    
   // serverIP地址为"136.149.3.29",注意使用inet_addrIP地址转换为网络格式 
    
      ServerAddr.sin_family = AF_INET; 
    
      ServerAddr.sin_port = htons(Port);     
    
      ServerAddr.sin_addr.s_addr = inet_addr("136.149.3.29"); 
    

   
    
      
   
   // 向server发出连接请求 
    
      connect(s, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr)); 
    
       
    
   // 新的连接建立后,就能够互相通信了,在这个简单的样例中,我们直接关闭连接, 
    
   // 并关闭监听Socket,然后退出应用程序 
    
      closesocket(s); 
    

   
    
      
   
   // 释放Windows Socket DLL的相关资源 
    
      WSACleanup(); 
    

}



 

23 WSAAsyncSelect模式

              前面说过,Windows网络编程模式有好几种,他们各有特点,实现起来复杂程度各不同样,适用范围也不一样。下图是Network Programming for Microsoft Windows 2nd 一书中对不同模式的一个性能測试结果。server採用Pentium 4 1.7 GHz XeonCPU768M内存;client有3PC,配置各自是Pentium 2 233MHz 128 MB 内存,Pentium 2 350 MHz 128 MB内存,Itanium 733 MHz 1 GB内存。























              详细的结果分析大家能够看看原书中作者的叙述,我关心的是哪种模式是我须要的。首先是server,勿庸置疑,肯定是完毕port模式。那么client呢,当然也能够採用完毕port,可是不同模式是在不同的操作系统下支持的,看下图:






              完毕port在Windows 98下是不支持的,尽管我们能够假定全部的用户都已经装上了Windows 2000Windows XP,。可是,假设是商业程序,这样的想法在现阶段不应该有,我们不能让用户为了使用我们的client而去升级他的操作系统。Overlapped I/O能够在Windows 98下实现,性能也不错,可是实现和理解起来快赶上完毕port了。并且,最关键的一点,client程序不是用来进行大规模网络响应的,client的主要工作应该是进行诸如图形运算等非网络方面的任务。原书作者,包含我强烈推荐大家使用WSAAsyncSelect模式实现client,由于它实现起来比較直接和easy,并且他全然能够满足client编程的需求。

              以下是一段源码,尽管我们是用它来写client,我还是把它的服务端代码放上来,一方面是有兴趣的朋友能够用他做測试和了解怎样用它实现server;还有一方面是client的代码能够非常easy的从它改动而成,不同的地方仅仅要參考一下2.1节里的代码就知道了。



 

#define WM_SOCKET WM_USER + 1 
    
#include <winsock2.h> 
    
#include <windows.h> 
    

   
    
      
   
int WINAPI WinMain(HINSTANCE hInstance, 
    
    HINSTANCE hPrevInstance, LPSTR lpCmdLine, 
    
    int nCmdShow) 
    
{ 
    
    WSADATA wsd; 
    
    SOCKET Listen; 
    
    SOCKADDR_IN InternetAddr; 
    
    HWND Window; 
    
    // 创建主窗体 
    

   
    
      
   
    Window = CreateWindow(); 
    
    // 初始化Windows Socket 2.2 
    
WSAStartup(MAKEWORD(2,2), &wsd); 
    

   
    
      
   
// 创建监听Socket 
    
    Listen = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    

   
    
      
   
    // 设置server地址 
    
    InternetAddr.sin_family = AF_INET; 
    
    InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    
    InternetAddr.sin_port = htons(5150); 
    

   
    
      
   
    // 绑定Socket 
    
    bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)); 
    

   
    
      
   
    // 设置Windows消息,这样当有Socket事件发生时,窗体就能收到相应的消息通知 
    
// server一般设置 FD_ACCEPT │ FD_READ | FD_CLOSE 
    
// client一般设置 FD_CONNECT │ FD_READ | FD_CLOSE 
    
    WSAAsyncSelect(Listen, Window, WM_SOCKET, FD_ACCEPT │ FD_READ | FD_CLOSE); 
    

   
    
      
   
   // 開始监听 
    
   listen(Listen, 5); 
    

   
    
      
   
    // Translate and dispatch window messages 
    
    // until the application terminates 
    
    while (1) { 
    
     // ... 
    
 } 
    
} 
    

   
    
      
   
BOOL CALLBACK ServerWinProc(HWND hDlg,UINT wMsg, 
    
    WPARAM wParam, LPARAM lParam) 
    
{ 
    
    SOCKET Accept; 
    

   
    
      
   
    switch(wMsg) 
    
    { 
    
        case WM_PAINT: 
    
            // Process window paint messages 
    
            break; 
    

   
    
      
   
        case WM_SOCKET: 
    
            // Determine whether an error occurred on the 
    
            // socket by using the WSAGETSELECTERROR() macro 
    

   
    
      
   
            if (WSAGETSELECTERROR(lParam)) 
    
            { 
    
                 // Display the error and close the socket 
    
                closesocket( (SOCKET) wParam); 
    
                break; 
    
            } 
    

   
    
      
   
            // Determine what event occurred on the 
    
            // socket 
    

   
    
      
   
            switch(WSAGETSELECTEVENT(lParam)) 
    
            { 
    
                case FD_ACCEPT: 
    

   
    
      
   
                    // Accept an incoming connection 
    
                    Accept = accept(wParam, NULL, NULL); 
    

   
    
      
   
                    // Prepare accepted socket for read, 
    
                    // write, and close notification 
    

   
    
      
   
                    WSAAsyncSelect(Accept, hDlg, WM_SOCKET, 
    
                        FD_READ │ FD_WRITE │ FD_CLOSE); 
    
                    break; 
    

   
    
      
   
                case FD_READ: 
    
                    // Receive data from the socket in 
    
                    // wParam 
    
                    break; 
    

   
    
      
   
                case FD_WRITE: 
    
                    // The socket in wParam is ready 
    
                    // for sending data 
    
                    break; 
    

   
    
      
   
                case FD_CLOSE: 
    
                    // The connection is now closed 
    
                    closesocket( (SOCKET)wParam); 
    
                    break; 
    
            } 
    
            break; 
    
    } 
    
    return TRUE; 
    

}



 



 

24 小节

              眼下为止,我非常简要的介绍了Windows网络编程的一些东西,附上了一些源码。能够说,读者特别是刚開始学习的人,看了后不一定就能立即写出程序来,而那些代码也不是能够直接应用于实际的项目。别急,万里长征才開始第一步呢,非常多书里都是依照基础到应用的顺序来写的,可是我喜欢更直接一点,更有用一些的方式。并且,我写的这个专题,毕竟不是商业化的,时间上不能投入过多,仅仅是作为给刚開始学习的人的一个小小帮助。很多其它的还是希望读者自己刻苦研究,有问题的时候能够到我的论坛上给我留言,以后有机会我也会发布一些实际的代码。希望结交很多其它热爱编程和中国游戏事业的朋友。下一章里我将主要解说完毕port编程,这也是我写这篇文章的初衷,希望对大家能有所帮助。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/118308.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • CSGO开箱网站大全_csgo哪个开箱网站能直接取

    CSGO开箱网站大全_csgo哪个开箱网站能直接取csgo开箱网站有哪些?csgo开箱网站大全##以下国内知名CSGO开箱网站官网直达链接优惠码/推广码网站状态incsgocsgogo直接取回skinsdogcsgogo直接取回88skinscsgo直接取回skskinscsgogo直接取回npskinscsgogo直接取回fateskinscsgo直接取回yskins暂无可取回coolkaixiangcsgo直接取回piggycasecsgogo

    2022年10月6日
    0
  • 电磁场与电磁波实验 01 – | 位移电流测量及电磁场与电磁波的存在实验[通俗易懂]

    电磁场与电磁波实验 01 – | 位移电流测量及电磁场与电磁波的存在实验[通俗易懂]一、实验目的 1、认识时变电磁场,理解电磁感应的原理和作用 2、理解电磁波辐射原理 3、了解位移电流的概念 二、预习要求 1、什么是法拉第电磁感应定律? 2、半波振子天线的原理。 三、实验仪器 HD-CB-V电磁场电磁波数字智能实训平台:1套 电磁波传输电缆:1套; 平板极化天线:1副; 半波振子天线:1副 (…

    2025年6月29日
    0
  • execute,executeQuery和executeUpdate的区别

    execute,executeQuery和executeUpdate的区别在jdbc中有3种执行sql的语句分别是execute,executeQuery和executeUpdateexecute执行增删改查操作execute返回的结果是个boolean型,当返回的是true的时候,表明有ResultSet结果集,通常是执行了select操作,当返回的是false时,通常是执行了insert、update、delete等操作。execute通常用于执行不明确的s

    2022年10月19日
    0
  • Dreamweaver 2020安装教程[通俗易懂]

    Dreamweaver 2020安装教程[通俗易懂]装前先关闭杀毒软件和360卫士,注意安装路径不能有中文,安装包路径也不要有中文。1.鼠标右击【Dreamweaver2020】压缩包选择【解压到Dreamweaver2020】。2.双击打开解压后的【Dreamweaver2020】文件夹。3.双击打开【setup】文件夹。4.鼠标右击【Set-up】选择【以管理员身份运行】。5.点击【继续】。6.点击文件夹图标,然后点击【更改位置】更改安装路径。7.建议安装在除…

    2022年5月25日
    37
  • 蹲坑的正确姿势是什么_trace设计软件

    蹲坑的正确姿势是什么_trace设计软件       正确姿势使用TraceView工具  在对手机应用性能分析和定位的过程中Traceview是使用最多的一个工具,在遇到启动时间长界面切换时间长特别卡顿的时候Traceview是首选工具。如果查看界面的帧率问题建议还是先使用GPU配置文件以列表的形式展示在屏幕上这样可以首先发现这个界面的帧率是否有问题再做后续的排查。如何开启TraceView  …

    2022年10月22日
    0
  • java 配置事务回滚_Spring@Transactional事务回滚

    java 配置事务回滚_Spring@Transactional事务回滚Spring中事务分为编程时事务和声明式事务,编程式事务:编程人员通过代码控制事务的开启、回滚、提交,声明式事务:把事务的处理交给spring。使用注解@transactional配置就是声明式事务。基本配置在applicationContext.xml配置文件中1//配置spring的DataSourceTransactionManager事务管理器23class=”org…

    2022年10月21日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号