复制本文链接

计算机网络,就是把分布在不同区域的计算机用通信线路连接在一起、可以方便地互相传递信息,共享资源。网络编程,就是直接或间接地通过网络协议与其他计算机进行通讯

网络编程中有两个重要问题:

  1. 如何准确地定位网络上一台或多台主机。
  2. 找到主机后如何可靠高效地进行数据传输。

基础术语

  • IP地址

网络中每台主机都必须有一个唯一的IP地址,IP地址是一个逻辑地址。
英特网上的IP地址具有全球唯一性。
32位,四个字节,常用点分十进制的格式表示。例如:113.45.153.190

  • 协议

为进行网络中的数据交换(通信)而建立的规则、标准或约定。(=语义+语法+规则)。
不同层具有各自不同的协议。

  • 端口

    在互联网上传输的数据都包含有用来识别目的地的IP地址和端口号
    IP地址用来标识网络上的计算机,而端口号用来指明该计算机上的应用程序
    端口用一个整数型标识符来表示,即端口号。
    端口使用一个16位的数字来表示,它的范围是0~655351024以下的为保留端口

  • 数据封装

一台计算机要发送数据到另一台计算机,数据首先必须打包,打包的过程称为封装
封装就是在数据前面加上特定的协议头部
在每一层传递信息的过程中都会进行一次封装,服务端收到信息后然后进行一层一层的解封装最终得到数据。

ISO七层模型

网络体系结构解决异质性问题采用的是分层的方法——把复杂的网络互联问题划分为若干个较小的、单一的问题,在不同层上予以解决,各层之间是严格的单向依赖。

  • OSI(Open System Interconnection)参考模型7层:
  • OSI各层所使用的协议:

应用层:Telnet、FTP、HTTP、DNS、SMTP、POP3
传输层:TCP、UDP
网络层:IP、ICMP、IGMP

详细讲解可查看博客:http://blog.csdn.net/yaopeng_2005/article/details/7064869

TCP/UDP

套接字Socket,是连接运行在网络上的两个程序间的双向通讯的端点。网络通信其实就是Socket间的通信。即,数据在两个Socket间通过IO传输

UDP

  • UDP支持更简单的、快速的、点对点的数据报模式

将数据及源和目的封装成数据包中 不需要建立连接
无连接,即是不可靠协议速度快
协议并不保证数据报是否能正确地到达目的地
每个数据报的大小在限制在64KB内

  • 实例一 、简单的接收和发送数据DEMO
  1. 发送数据

 

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * 通过udp协议发送数据
 * Created by xiaoxiaomo on 2016/4/12.
 *
 */
public class UdpSendSimpleDemo {

  /**
   * 1:获取socket对象
   * 2:对数据进行封包
   * 3:通过socket对象把数据包发送出去
   * 4:把连接关闭
   * @param args
   */
  public static void main(String[] args) throws IOException {

    //1. 获取socket对象
    DatagramSocket ds = new DatagramSocket();

    //2. 封包数据
    String sendMsg = "UDP ......你好!" ;

    /**
     * @param buf 字节流数据包
     * @param length 流数据包长度 eg,InetAddress.getByName("192.168.3.102")
     * @param address  发送地址
     * @param port 端口号
     */
    DatagramPacket p =
        new DatagramPacket(sendMsg.getBytes(),sendMsg.getBytes().length,InetAddress.getLocalHost(),3000);

    //3. 发送数据包
    ds.send(p);

    //4. 关闭连接
    ds.close();
  }
}

2 接收数据

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * UDP接收端代码
 * Created by xiaoxiaomo on 2016/4/12.
 *
 */
public class UdpReceiveSimpleDemo {
  /**
   * 1:获取socket连接(需要指定监听的端口)
   * 2:通过receive方法接收数据包
   * 3:解包,获取数据包中的内容
   * 4:关闭连接
   * @param args
   * @throws Exception 
   */
  public static void main(String[] args) throws IOException {
    //1:获取连接
    DatagramSocket ds = new DatagramSocket(3000);;

    //2:接收数据
    byte[] buf = new byte[1024];
    DatagramPacket p = new DatagramPacket(buf, 0, buf.length);
    ds.receive(p);

    //3:获取数据
    System.out.println( "信息来源:"+p.getAddress().getHostAddress() );
    System.out.println( "收到数据:" + new String( p.getData(),0,p.getLength()) );

    //4:关闭连接
    ds.close();
  }
}

3 运行结果

如果先运行UdpSendSimpleDemo没有任何信息
如果先运行UdpReceiveSimpleDemo会输出:
信息来源:192.168.3.102
收到数据:UDP ......你好!

 

  • 实例二 、相对复杂的实例

发送数据后,如果不成功会继续发送4次,都不成功则表示失败。
接收端收到信息后,会返回消息告诉发送者已成功,发送者收到数据会进行相应的校验。

  1. 发送数据
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.*;

/**
 * 通过udp协议发送数据
 * Created by xiaoxiaomo on 2016/4/12.
 *
 */
public class UdpSendDemo {
  private static final int TIMEOUT = 3000;  //设置接收数据的超时时间
  private static final int MAXNUM = 5;      //设置重发数据的最多次数
  /**
   * 1:获取socket对象
   * 2:对数据进行封包
   * 3:通过socket对象把数据包发送出去
   * 4:把连接关闭
   * @param args
   */
  public static void main(String[] args) {

    //1. 获取socket对象
    DatagramSocket ds = null;
    try {
      ds = new DatagramSocket(9000); //如果只是用于发送不填写端口
    } catch (SocketException e) {
      System.out.println("创建一个socket对象失败!");
    }

    //2. 封包数据
    String sendMsg = "UDP ......你好!" ;

    DatagramPacket p = null;
    try {
      p = new DatagramPacket(sendMsg.getBytes(),sendMsg.getBytes().length,InetAddress.getLocalHost(),3000);
    } catch (UnknownHostException e) {
      System.out.println("找不到该hosts所对应的地址!");
    }

    //3. 发送数据包
    boolean isReceived = false; //是否接收到数据的标志位
    int tries = 0;  //重发数据的次数
    try {
      ds.setSoTimeout(TIMEOUT); //设置超时时间
      //直到接收到数据,或者重发次数达到预定值,则退出循环
      while(!isReceived && tries<MAXNUM) {

        ds.send(p); //发送数据

        try{
          //定义用来接收数据的DatagramPacket实例
          DatagramPacket dp_receive = new DatagramPacket(new byte[1024], 1024);
          //接收从服务端发送回来的数据
          ds.receive(dp_receive);
          //如果接收到的数据不是来自目标地址,则抛出异常
          if(!dp_receive.getAddress().equals( InetAddress.getLocalHost() )){
            throw new IOException("地址出错");
          }
          //如果接收到数据。则将receivedResponse标志位改为true,从而退出循环
          isReceived = true;
        }catch(InterruptedIOException e){
          //如果接收数据时阻塞超时,重发并减少一次重发的次数
          tries += 1;
          System.out.println("Time out,次数:" + tries );
        }
      }
    } catch (IOException e) {
      System.out.println("发送数据失败!");
    }


    if(isReceived){
      //成功
      System.out.println("发送成功!");
    }else{
      //失败
      System.out.println("重发信息"+tries+"次后,失败!");
    }


    //4. 关闭连接
    if( ds != null ){
      ds.close();
    }
  }

}

2 接收数据

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * UDP接收端代码
 * Created by xiaoxiaomo on 2016/4/12.
 *
 */
public class UdpReceiveDemo {
  /**
   * 1:获取socket连接(需要指定监听的端口)
   * 2:通过receive方法接收数据包
   * 3:解包,获取数据包中的内容
   * 4:关闭连接
   * @param args
   * @throws Exception 
   */
  public static void main(String[] args) {
    //1:获取连接
    DatagramSocket ds = null;
    try {
      //在3000端口监听接收到的数据
      ds = new DatagramSocket(3000);
    } catch (SocketException e) {
      //例如,该端口已被占用
      //java.net.BindException: Address already in use: Cannot bind
      System.out.println("创建一个socket对象失败!"+e.getMessage());
    }

    //这些让它一直接收数据
    while( ds != null ){

      //2:接收数据
      byte[] buf = new byte[1024];
      DatagramPacket p = new DatagramPacket(buf, 0, buf.length);
      try {
        ds.receive(p);
      } catch (IOException e) {
        //例如,ds为空等
        System.out.println("接收数据失败!");
      }

      //3:获取数据
      System.out.println( "信息来源:"+p.getAddress().getHostAddress() );
      System.out.println( "收到数据:" + new String( p.getData(),0,p.getLength()) );


      //通知9000端口的客户端数据接收成功
      //数据发动到客户端的
      DatagramPacket dp_reply= new DatagramPacket(p.getData() ,p.getData().length,p.getAddress(),9000);
      try {
        ds.send(dp_reply);
      } catch (IOException e) {
        e.printStackTrace();
      }
      //由于dp_reply在接收了数据之后,其内部消息长度值会变为实际接收的消息的字节数,
      //所以这里要将dp_reply的内部消息长度重新置为1024
      dp_reply.setLength(1024);
    }
    //4:关闭连接
    //ds.close();
  }
}

 

3 运行结果

UdpSendDemo先运行,如中途UdpReceiveDemo还未启动则运行结果:
Time out,次数:1
Time out,次数:2
Time out,次数:3
Time out,次数:4
Time out,次数:5
重发信息5次后,失败!
UdpReceiveDemo先运行,UdpSendDemo会收到发送成功!接收者
信息来源:192.168.3.102
收到数据:UDP ......你好!

 

TCP

  • TCP用于网络的可靠的流式输入/输出,HTTP、FTP、Telnet等应用都需要这种可靠的通信通道。、

两个socket之间必须建立连接形成传输数据的通道
在连接中进行大数据量传输
通过三次握手完成连接 是可靠协议效率会稍低

  • 事例一、简单的TCP实例
  1. TCP发送端
  2. import java.io.OutputStream;
    import java.net.Socket;
    
    /**
     * TCP发送端
     * Created by xiaoxiaomo on 2016/4/12.
     */
    public class TcpSendSimpleDemo {	
      /**
       * 1:创建socker客户端,需要连接到接收端
       * 2:获取这个socket的输出流
       * 3:通过输出流给其他服务器发送数据
       * 4:关键连接
       * @param args
       * @throws Exception 
       */
      public static void main(String[] args) throws Exception {
        //1:获取socker对象
        Socket socket = new Socket("192.168.3.102",6000);
    
        //2:获取输出流
        OutputStream outputStream = socket.getOutputStream();
    
        //3:通过输出流写数据
        outputStream.write("TCP ... 你好!".getBytes());
    
        //4:关闭连接
        socket.close();
      }
    }

     

  3. TCP接收端
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * TCP接收端
     * Created by xiaoxiaomo on 2016/4/12.
     */
    public class TcpReceiveSimpleDemo {	
      /**
       * 1:创建一个socket服务端,需要监听指定端口
       * 2:通过这个服务端对象可以获取到给指定端口发送数据的socket客户端对象
       * 3:通过socket对象获取具体的读取流
       * 4:通过读取流获取数据
       * 5:关闭连接
       * @param args
       * @throws Exception 
       */
      public static void main(String[] args) throws Exception {
        //1:获取ServerSocket
        ServerSocket serverSocket = new ServerSocket(6000);
    
        //2:获取客户端的socket对象
        //是一个阻塞方法,获取socket客户端对象
        Socket socket = serverSocket.accept();
    
        //3:获取socket的输入流
        InputStream in = socket.getInputStream();
        byte[] bytes = new byte[1024];
    
        //4:读取数据
        int read = in.read(bytes);
        System.out.println(new String(bytes, 0, read));
    
        //5:关闭连接
        socket.close();
        serverSocket.close();
      }
    }
    

     

    InetAddr类讲解:Java-网络编程InetAddr和URL

TCP/IP模型

阿里云老用户专享阿里云双12 阿里云双12

发表评论

电子邮件地址不会被公开。 必填项已用*标注

55 − 46 =