zoukankan      html  css  js  c++  java
  • VC++ 网络编程总结(一)

    1、套接字编程原理

            一个完整的网间通信进程需要由两个进程组成,并且只能用同一种高层协议。也就是说,不可能通信的一段用TCP,而另一端用UDP。一个完整的网络信息需要一个五元组来标识:协议、本地地址、本地端口号、远端地址、远端端口号。

    1.1Client/Server通信模型

            在客户端/服务器模式中我们将请求服务的一方成为客户,将提供某种服务的一方称为服务器(Server)

           一个服务程序通常在一个众所周知的地址监听对服务的请求,也就是说服务进程一直处于休眠状态,直到一个客户对这个服务的地址提出了连接请求。在这个时刻,服务程序被“惊醒”,并且为客户提供服务----对客户的请求做出适当的反应。虽然基于链接的服务是设计客户机/服务器应用程序时的标准,但有些服务也是可以通过无连接的接口提供的。

             客户及/服务器的请求/响应过程示意图如下所示:

                     2013-08-18_094539

    1.2Windows Sockets规范

            Windows Sockets规范从90年代的1.0版本开始,经过不断的完善和发展,目前已经有了Windows Sockets 2版本。值得注意的是,Microsoft的MFC库现在只支持Windows Sockets1版本,不支持WindowsSockets2版本。

            MFC提供了两个类用以封装Windows Sockets API。一个是CAsyncSocket类,它主要是提供给那些具有一定网络编程经验,希望同时拥有Socket API编程的灵活性和类库编程便利性的开发者。另一个是CSocket类,它有CAsyncSocket类派生,它具有更高的抽象化,致力于简化网络编程所需的操作。

    1.3套接字

    1.3.1套接字定义

          套接字是一个通信终结点,它是Sockets应用程序用来在网络上发送或接收数据包的对象。套接字具有类型,与正在运行的进程相关联,并且可以有名称。目前,套接字一般只与使用网际协议组的同一“通信域”中德其他套接字交换数据。使用套接字的应用程序间通信模型如图:

                    2013-08-18_095755

    1.3.2分类

       1.3.2.1流式套接字

           流式套接字提供没有记录边界的数据流,即字节流。字节流能确保以正确的顺序无重复地被送达。

    2013-08-18_100404

    1.3.2.2数据报套接字

            数据报套接字支持面向记录的数据流,但不能确保能被送达,也无法确保按照发送顺序或不重复。

           2013-08-19_172014

         “有序”指数据包按发送的顺序送达。“不重复”指一个特定的数据包只能获取一次。这两种套接字都是双向,是可以同时在两个方向上(全双工)进行通信的数据流.

           注意:在某些网络协议下(如XNS),流可以面向记录,即作为记录流而非字节流。但在更常用的TCP/IP协议下,流为字节流,Win Sockets提供与基础协议无关的抽象化级别。

    1.3.3套接字的作用

          套接字的作用非常大,至少在下面三种通信上下文中如此:

    • 客户端/服务器模型
    • 对等网络方案,如聊天应用程序
    • 通过让接受应用程序将消息解释为函数调用来进行远程过程调用

    1.3.4 端口与地址

         在网络上,一个套接字的标识主要借助于地址和端口来描述。

         套接字的地址指该套接字所在计算机的网络地址,可以为域名或IP地址的形式。通常创建套接字时不必指明网络地址,只有在拥有多个网络地址的机器时,才需要显式指定的一个网络地址。

          同一机器上可以运行多个网络应用程序,每个应用程序都有自己的套接字用以进行网络通信,此时如果只有地址表示套接字,则当一个通信包到达机器时,将无法确定究竟是哪个应用程序的套接字需要接收此信息。由此增加了端口的概念,以协助区分同一机器上不同应用程序的套接字。

          段开口用于标识进程,同一机器上不同的网络应用程序各有不同的端口,这样,通过“网络地址+端口号”的标识方法,便唯一标识了机器上的应用程序了。

    实例应用程序:

    ======客户端

    #include < WINSOCK2.H> 
    #pragma comment( lib, "WS2_32" ) 
    #include < stdio.h> 
    
    int main() 
    { 
         printf( "------------------------
    | 客户端 |
    |---------------------------------------
    " ); 
         //------①加载动态链接库winsock DLL-----------
         printf( "|加载等待中.... " ); 
         WSADATA wsaData; 
         WORD wVersionRequested= MAKEWORD( 2 ,2 ); 
         if ( WSAStartup( wVersionRequested,& wsaData)!= 0 )
         { 
             printf( "|WSAStartup Failed
    " ); 
             printf( "|WSAStartup Error=%d
    " , WSAGetLastError()); 
         } 
         else 
         { 
             printf( "加载Winsock 库成功 |
    " ); 
         } 
         printf( "|---------------------------------------
    " ); 
         //-------②创建用于监听的流式套接口s,使用socket()-----------------
         SOCKET s= socket( AF_INET, SOCK_STREAM, IPPROTO_TCP); 
         if ( s== INVALID_SOCKET) 
         { 
             printf( "|Failed socket
    " ); 
             printf( "|socket Error=%d
    " , WSAGetLastError()); 
         } 
         else 
             printf( "|已创建用于监听的套接口,套接口号:[%u]
    " , s); 
         printf( "|---------------------------------------
    " ); 
         //------③本地地址bind(可以不做这部分,如果不绑定,系统将自动分配)--------
         /*struct sockaddr_in Cadd;
         Cadd.sin_family=AF_INET;
         Cadd.sin_port=htons(4444);
         Cadd.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
         if (bind(s,(sockaddr*)&Cadd,sizeof(Cadd))==SOCKET_ERROR)
         {
             printf("|Failed bind()/n");
         }*/ 
         //-------填写要连接的服务器地址信息---------
         struct sockaddr_in Sadd; 
         Sadd.sin_family= AF_INET; 
         Sadd.sin_port= htons( 5555 ); 
         Sadd.sin_addr.S_un.S_addr= inet_addr( "127.0.0.1" ); 
         //--------④将套接口s与远程主机相连--------------
         if ( connect( s,( sockaddr*)& Sadd, sizeof ( Sadd))== INVALID_SOCKET) 
         { 
             printf( "|Failed connect()
    " ); 
             printf( "|connect Error=%d
    " , WSAGetLastError()); 
         } 
         else 
         { 
             //####################开始发接数据########################
             printf( "|连接成功,可以开始发送接收数据了!
    " ); 
             printf( "|服务器IP地址:[%s]
     端口号:[%u]
    " , inet_ntoa( Sadd.sin_addr), ntohs( Sadd.sin_port)); 
             //####################结束发接数据########################
         } 
         //--------------⑤关闭套接字s,终止对动态链接库的访问----------
         closesocket( s); 
         printf( "|---------------------------------------
    " ); 
         printf( "|连接完毕
    " ); 
         WSACleanup(); 
         return 0 ;
    }

    ========服务端

    #include <winsock2.h>
    #include <stdio.h>
    #pragma comment(lib,"ws2_32")
    
    int main(int argc, char* argv[])
    {
        printf("---------
    | 服务端 |
    -----------");
        //----------1、加载动态链接库Winsock Dll---------
        WORD wVersionRequested = MAKEWORD(2,2);
        WSADATA wsaData;
        if(WSAStartup(wVersionRequested,&wsaData) != 0)
        {
            printf("WSAStartup Failed 
    ");
            printf("WSAStartup Error = %d 
    ",WSAGetLastError());
        }
        else
        {
            printf("加载WinSocket成功 
    ");
            printf("调用者希望使用的WinSocket版本号=%x
    ",wsaData.wVersion);
            printf("加载的WinSock库支持最高WinSock版本号=%x 
    ",wsaData.wHighVersion);
            printf("wWinSock库的说明字符串=%s 
    ",&wsaData.szDescription[0]);
            printf("系统状态或配置信息的说明字符串=%s
    ",&wsaData.szSystemStatus[0]);
        }
        //----------2、创建监听的流式套接口----------
        
        SOCKET s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(s == INVALID_SOCKET)
        {
            printf("| Failed socket
    ");
            printf("| Socket Error = %d
    ",WSAGetLastError());
        }
        else
            printf("毅创建用于监听的套接口,套接口号:[%u]
    ",s);
    
        //----3、绑定使用bind()
        struct sockaddr_in Sadd;
        Sadd.sin_family = AF_INET;
        Sadd.sin_port = htons(5555);
        Sadd.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        if(bind(s,(sockaddr*)&Sadd,sizeof(Sadd)) == SOCKET_ERROR)
        {
            printf("Failed bind()
    ");
            printf("Bind Error = %d
    ",WSAGetLastError());
        }
        else
        {
            printf("绑定成功
    ");
            printf("本地Ip地址:[%s],本地端口号:[%u]
    ",inet_ntoa(Sadd.sin_addr),ntohs(Sadd.sin_port));
        }
        //---------------④监听状态-------------
         if ( listen( s, 2 )== SOCKET_ERROR) 
         { 
             printf( "Failed listen()
    " ); 
             printf( "listen Error=%d
    " , WSAGetLastError()); 
         } 
         //----------------⑤循环接受客户的连接请求---------------------------
         struct sockaddr_in Cadd; 
         int caddLen= sizeof ( Cadd); 
         SOCKET c; 
         while ( TRUE ) 
         { 
             printf( "|----------------------------
    " ); 
             printf( "|进入监听状态.....
    |--------------------------------|
    " ); 
             c= accept( s,( sockaddr*)& Cadd,& caddLen); 
             if ( c== INVALID_SOCKET) 
             { 
                 printf( "|Failed accept()
    " ); 
                 printf( "|accept Error=%d
    " , WSAGetLastError()); 
             } 
             else 
                 printf( "|可以在套接口[%u]上发送接收数据了!
    " , c); 
             //#########################开始发送、接收###################### 注意都要在新套接口c上进行
             //#########################结束发送、接收######################
             closesocket( c); 
             printf( "|与主机IP地址是:[%s]
    |端口号是:[%u]的连接完毕
    " , inet_ntoa( Cadd.sin_addr), ntohs( Cadd.sin_port)); 
             char xx; 
             printf( "|-------------------------------------
    需要退出吗?(Y
    )" ); 
             scanf( "%c" ,& xx); 
             if ( xx== 'Y' || xx== 'y' ) 
             { 
                 break ; 
             } 
         } 
         closesocket( s); 
         WSACleanup();
        return 0;
    }

    运行结果:

    2013-08-19_1742062013-08-19_174227

  • 相关阅读:
    交叉编译环境软件搭建
    (C)struct结构体
    (C)字节对齐#pragma pack()
    常用bluetooth协议
    (C/C++)register关键字
    Android学习
    (C)*p++和*++p区别
    java文件末尾追加内容的两种方式
    java1.7集合源码阅读: Stack
    java1.7集合源码阅读: Vector
  • 原文地址:https://www.cnblogs.com/haoyuanyuan/p/3268351.html
Copyright © 2011-2022 走看看