zoukankan      html  css  js  c++  java
  • 网络编程

      网络程序的实现可以有多种方式,Windows Socket就是其中一种比较简单的实现方法.Socket是连接应用程序与网络驱动程序的桥梁,Socket在应用程序中创建.通过绑定操作与驱动程序建立关系。此后应用程序送给Socket的数据,由Socket交给驱动程序向网络上发送出去.计算机从网络上收到与该Socket绑定的IP地址和端口号相关的数据后,由驱动程序交给Socket,应用程序便可从该Socket中提取接收到的数据。网络应用程序就是这样通过Socket进行数据的发送与接收的。
      两台主机要进行通信,要遵循约定的规则,我们把这种规则称之为协议。为了标识在计算机上运行的每一个网络通信程序,为他们分别分配一个端口号。在发送数据时,除了指定接收数据的主机IP地址外,还要指定相应的端口号。这样,在指定IP地址的计算机上,将会由在指定端口号上等待数据的网络应用程序接收数据。
    传输层:传输控制协议(TCP),用户数据报协议(UDP)
    TCP:面向连接的可靠的传输协议。利用TCP协议进行通信时,首先要通过三步握手,以建立通信双方的连接。一旦连接建立好,就可以进行通信了。TCP提供了数据确认和数据重传的机制,保证了发送的数据一定能到达通信的对方。
    UDP:是无连接的、不可靠的传输协议。采用UDP进行通信时,不需要建立连接,可以直接向一个IP地址发送数据,但是对方能否收到,就不敢保证了。我们知道在网络上传输的是电信号,既然是电信号,在传输过程中就会有衰减,因此数据有可能在网络上就消失了,也有可能我们所指定的IP地址还没有分配,或者该IP地址所对应的主机还没有运行,这些情况都有可能导致发送的数据接收不到。
      端口是一种抽象的软件结构(包括一些数据结构和I/O缓冲区).应用程序通过系统调用与端口建立连接(binding)后,传输层传给该端口的数据都被相应的进程所接收,相应进程发给传输层的数据都通过该端口输出。端口用一个整数型标识符来表示,即端口号。端口号跟协议相关,TCP/IP传输层的两个协议TCP和UDP是完全独立的两个软件模块,因此各自的端口号也相互独立。端口使用一个16位的数字来表示,它的范围是0-65535,1024以下的端口号保留给预定义的服务。例如,http使用80端口。
      不同的计算机存放多字节值的顺序不同,有的机器在起始地址存放低位字节(低位先存),有的机器在起始地址存放高位字节(高位先存)。基于Intel的CPU,即我们常用的PC机采用的是低位先存。为保证数据的正确性,在网络协议中需要指定网络字节顺序,TCP/IP协议使用16位整数和32位整数的高位先存格式。由于不同的计算机存放数据字节的顺序不同,这样发送方发送数据后,即使接收方接收到该数据,也有可能无法查看所接收到的数据。所以在网络中不同主机间进行通信时,要统一采用网络字节顺序。
      在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户机/服务器模式(CliendServer),即客户向服务器提出请求,服务器接收到请求后,提供相应的服务。
    客户机/服务器模式的建立基于以下两点:首先,建立网络的起因是网络中软硬件资源、运算能力和信息不均等,需要共享,从而造就拥有众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用。其次,网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是基于客户机/服务器模式的TCP/IP.
    一、套接字的类型
    1.流式套接字(SOCK_STREAM)
    提供面向连接、可靠的数据传输服务,数据无差错、无重复的发送,且按发送顺序接收。流式套接字实际上是基于TCP协议实现的。
    2.数据报式套接字(SOCK_DGRAM )
    提供无连接服务。数据包以独立包形式发送,不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。数据报式套接字实际上是基于UDP协议实现的。
    3.原始套接字(SOCK_RAW)
    二、基于TCP(面向连接)的socket编程
    服务器端程序流程如下:
    1.创建套接字(socket)。
    2.将套接字绑定到一个本地地址和端口上(bind)。
    3.将套接字设为监听模式,准备接收客户请求(listen)。
    4.等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)。
    5.用返回的套接字和客户端进行通信(send/recv)。
    6.返回,等待另一客户请求。
    7.关闭套接字。
    基于TCP(面向连接)的socket编程的客户端程序流程如下:
    1.创建套接字(socket)。
    2.向服务器发出连接请求(connect)。
    3.和服务器端进行通信(send/recv )。
    4.关闭套接字。
      在服务器端,当调用accept函数时,程序就会等待,等待客户端调用Connect函数发出连接请求,然后服务器端接受该请求,于是双方就建立了连接。之后,服务器端和客户端就可以利用send和recv函数进行通信了。读者应注意,在客户端并不需要调用bind函数。因为服务器需要接收客户端的请求,所以必须告诉本地主机它打算在哪个IP地址和哪个端口上等待客户请求,因此必须调用bind函数来实现这一功能。而对客户端来说,当它发起连接请求,服务器端接受该请求后,在服务器端就保存了该客户端的IP地址和端口的信息。这样,对服务器端来说,一旦建立连接之后,实际上它己经保存了客户端的IP地址和端口号的信息,因此就可以利用所返回的套接字调用send/recv函数与客户端进行通信。
    三、基于UDP(面向无连接)的socket编程
    服务器端也叫接收端,对于基于UDP(面向无连接)的套接字编程来说,它的服务器端和客户端这种概念不是很强化,我们也可以把服务器端,即先启动的一端称为接收端,发送数据的一端称为发送端,也称为客户端。
    我们先看一下接收端程序的编写:
    1.创建套接字(socket )。
    2.将套接字绑定到一个本地地址和端口上(bind )。
    3.等待接收数据(recvfrom )。
    4.关闭套接字。
    对于基于UDP的套接字编程,为什么仍然需要调用bind函数进行绑定呢?应注意,虽然面向无连接的socket编程无须建立连接,但是为了完成这次通信,对于接收端来说,它必须先启动以接收客户端发送的数据,因此接收端必须告诉主机它是在哪个地址和端口上等待数据的到来,也就是说,接收端(服务器端)必须调用bind函数将套接字绑定到一个本地地址和端口上。
    对于客户端程序的编写非常简单:
    1.创建套接字(socket)。
    2.向服务器发送数据(sendto)。
    3.关闭套接字。
    注意,在基于UDP的套接字编程时,利用的是sendto和recvfrom这两个函数实现数据的发送和接收,而基于TCP的套接字编程时,发送数据是调用send函数,接收数据调用recv函数。
    套接字表示了通信的端点。我们利用套接字进行通信与利用电话机进行通信是一样的,套接字相当于电话机,IP地址相当于总机号码,而端口号则相当于分机。

    Win32Tcp:

    #include <Winsock2.h>
    #include <stdio.h>
    void main()
    {
      WORD wVersionRequested;
      WSADATA wsaData;
      int err;

      wVersionRequested = MAKEWORD( 1, 1 );
      err = WSAStartup( wVersionRequested, &wsaData );
      if ( err != 0 )
      {
        return;
      }

      if ( LOBYTE( wsaData.wVersion ) != 1 ||
      HIBYTE( wsaData.wVersion ) != 1 )
      {
        WSACleanup( );
        return;
      }
      SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);

      SOCKADDR_IN addrSrv;
      addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
      addrSrv.sin_family=AF_INET;
      addrSrv.sin_port=htons(6000);

      bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

      listen(sockSrv,5);

      SOCKADDR_IN addrClient;
      int len=sizeof(SOCKADDR);

      while(1)
      {
        SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
        char sendBuf[100];
        sprintf_s(sendBuf,"Welcome %s to http://www.sunxin.org",
        inet_ntoa(addrClient.sin_addr));
        send(sockConn,sendBuf,strlen(sendBuf)+1,0);
        char recvBuf[100];
        recv(sockConn,recvBuf,100,0);
        printf("%s ",recvBuf);
        closesocket(sockConn);
      }
    }

    Win32Client:

    #include <Winsock2.h>
    #include <stdio.h>

    void main()
    {
      WORD wVersionRequested;
      WSADATA wsaData;
      int err;

      wVersionRequested = MAKEWORD( 1, 1 );
      err = WSAStartup( wVersionRequested, &wsaData );
      if ( err != 0 )
      {
        return;
      }

      if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
      {
        WSACleanup( );
        return;
      }
      SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);

      SOCKADDR_IN addrSrv;
      addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
      addrSrv.sin_family=AF_INET;
      addrSrv.sin_port=htons(6000);
      connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

      char recvBuf[100];
      recv(sockClient,recvBuf,100,0);
      printf("%s ",recvBuf);
      send(sockClient,"This is lisi",strlen("This is lisi")+1,0);

      closesocket(sockClient);
      WSACleanup();
    }

    UDPSrv:

    #include <WinSock2.h>
    #include <stdio.h>
    void main()
    {
      WORD wVersionRequested;
      WSADATA wsaData;
      int err = 0;
      wVersionRequested = MAKEWORD(2,2);
      err = WSAStartup(wVersionRequested,&wsaData);
      if (0 != err)
      {
        return;
      }
      if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
      {
        WSACleanup();
        return;
      }

      SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0);
      SOCKADDR_IN addrSvr;
      addrSvr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
      addrSvr.sin_family = AF_INET;
      addrSvr.sin_port = htons(6000);

      bind(sockSrv,(SOCKADDR*)&addrSvr,sizeof(SOCKADDR));

      SOCKADDR_IN addrClient;
      int len = sizeof(SOCKADDR);
      char recvBuf[100] = "";
      recvfrom(sockSrv,recvBuf,sizeof(recvBuf),0,(SOCKADDR*)&addrClient,&len);
      printf(recvBuf);
      closesocket(sockSrv);
      WSACleanup();
    }

    UDPClient:

    #include <WinSock2.h>
    #include <stdio.h>

    void main()
    {
      WORD wVersionRequested;
      WSADATA wsaData;
      int nErr = 0;
      wVersionRequested = MAKEWORD(2,2);
      nErr = WSAStartup(wVersionRequested,&wsaData);
      if (0 != nErr)
      {
        return;
      }
      if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
      {
        WSACleanup();
        return;
      }

      SOCKET sockClient = socket(AF_INET,SOCK_DGRAM,0);
      SOCKADDR_IN sockSrc;
      sockSrc.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
      sockSrc.sin_family = AF_INET;
      sockSrc.sin_port = htons(6000);

      sendto(sockClient,"Hello",strlen("Hello")+1,0,(SOCKADDR*)&sockSrc,sizeof(sockSrc));
      closesocket(sockClient);
      WSACleanup();
    }

  • 相关阅读:
    DRUPAL-PSA-CORE-2014-005 && CVE-2014-3704 Drupal 7.31 SQL Injection Vulnerability /includes/database/database.inc Analysis
    WDCP(WDlinux Control Panel) mysql/add_user.php、mysql/add_db.php Authentication Loss
    Penetration Testing、Security Testing、Automation Testing
    Tomcat Server Configuration Automation Reinforcement
    Xcon2014 && Geekpwn2014
    phpMyadmin /scripts/setup.php Remote Code Injection && Execution CVE-2009-1151
    Linux System Log Collection、Log Integration、Log Analysis System Building Learning
    The Linux Process Principle,NameSpace, PID、TID、PGID、PPID、SID、TID、TTY
    Windows Management Instrumentation WMI Security Technology Learning
    IIS FTP Server Anonymous Writeable Reinforcement, WEBDAV Anonymous Writeable Reinforcement(undone)
  • 原文地址:https://www.cnblogs.com/fenghuan/p/4867871.html
Copyright © 2011-2022 走看看