Java学习--网络编程

 目录

  1.认识网络基本模型

  2.基于TCP协议的网络通信

  3.基于UDP协议的网络通信

  4.基于TCP/IP建立的协议

  5.总结

一、网络的基本模型

  OSI七层网络模型

  应用层:面向用户的个各种协议

  表示层:信息语法及之间的关联

  会话层:不同机器之间建立

  传输层:TCP、IP协议

  网络层:路由器

  数据链路层:网桥,交换机

  物理层:网卡,网线,集线器,中继器,调制解调器

需要详细了解OIS网络模型的请往这走:  https://blog.csdn.net/yaopeng_2005/article/details/7064869

   TCP/IP模型则是将OIS的模型合并成4层。

  下面是OISTCP/IP模型的对比图

  

二、基于TCP协议的网络编程

 

  首先我们要了解一下TCP协议。

  TCP协议是一种可靠的网络协议,它需要在通信双方建立socket从而形成网络连接。

  在TCP建立连接中经典的三次握手建立连接阶段可以用如下图表示:

  

  有新兴趣的可以往这边走https://blog.csdn.net/whuslei/article/details/6667471

在计算机网络通信中,我们需要找到具体的程序,通常使用ip+端口来寻找的。

ip可以找到我们的计算机,而端口则可以定位到这台计算机的某个程序,端口与进程是没有关联的,端口是用16位表示的

端口号范围    0-65535  

接下来我们看一下TCP通信的模型图吧:

  

套接字:用于主机的IP地址+主机的端口号作为TCP连接的端点,
着这种端点成为套接字。

   服务器端:ServerSocket类

   客户端:Socket类

废话不多说,我们先来搭建一个服务器端和客户端

package com.demo.tcp;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务器端
 * @author Administrator
 *
 */
public class ServerDemo {
    private ServerSocket server;
    private Socket socket;
    private int port = 8888;
    //构造函数中初始化服务器
    public ServerDemo() {
        // TODO Auto-generated constructor stub
        try {
            //这里利用构造方法初始化服务器,我这里只传了一个参数,所以本机相当于服务器
            server = new ServerSocket(port);
            System.out.println("服务器初始化完成...");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            System.out.println("服务器初始化失败");
        }
    }
    //服务器需要做的事
    public void server(){
        //因为服务器不能关,所以需要写个死循环来监听客户端的链接
        while(true){
            try {
                //监听客户端的链接,客户端链接进来程序才会继续执行
                socket = server.accept();
                System.out.println("客户端:"+socket);
                
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    public static void main(String[] args) {
        //启动服务器
        new ServerDemo().server();
    }
}
服务器端
package com.demo.tcp;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;

/**
 * 客户端
 */
public class ClickDemo {
    private Socket socket;
    private String host = "localhost";
    private int port = 8888;
    //客户端构造方法里连接服务器
    public ClickDemo() {
        // TODO Auto-generated constructor stub
        try {
            //客户端初始化需要设定服务器的ip(由于我这里是在同一台机器上,所以host指定的是本地),port端口需要与服务器的端口一致才能连接上
            socket = new Socket(InetAddress.getByName(host), port);
            System.out.println("链接成功");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            System.err.println("链接超时");
        }
    }
    

    public static void main(String[] args) {
        //启动客户端
        new ClickDemo();
    }
}
客户端

服务器和客户端链接之后都会有一个Socket对象,我们看看官方是怎样解释socket对象的

在我看来,套接字相当于通信的工具,我们可以通过这个通信工具来收发信息

继续查看API可以看到有一个getInputStream和一个getOutputStream方法,这两个方法

则是我们用来收发信息的方法。

接下来我们写一个简单的信息传输实例吧

package com.demo.tcp;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

/**
 * 客户端
 */
public class ClickDemo {
    private Socket socket;
    private String host = "localhost";
    private int port = 8888;
    //客户端构造方法里连接服务器
    public ClickDemo() {
        // TODO Auto-generated constructor stub
        try {
            //客户端初始化需要设定服务器的ip(由于我这里是在同一台机器上,所以host指定的是本地),port端口需要与服务器的端口一致才能连接上
            socket = new Socket(InetAddress.getByName(host), port);
            System.out.println("链接成功");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            System.err.println("链接超时");
        }
    }
    
    public void send(String context){
        try {
                OutputStream os = socket.getOutputStream();
                PrintWriter pw = new PrintWriter(os);
                pw.println(context);
                pw.flush();
                System.out.println("发送成功");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("发送失败");
        }
        
    }

    public static void main(String[] args) {
        //启动客户端
        new ClickDemo().send("HelloWord");
    }
}
客户端
package com.demo.tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务器端
 * @author Administrator
 *
 */
public class ServerDemo {
    private ServerSocket server;
    private Socket socket;
    private int port = 8888;
    //构造函数中初始化服务器
    public ServerDemo() {
        // TODO Auto-generated constructor stub
        try {
            //这里利用构造方法初始化服务器,我这里只传了一个参数,所以本机相当于服务器
            server = new ServerSocket(port);
            System.out.println("服务器初始化完成...");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            System.out.println("服务器初始化失败");
        }
    }
    //服务器需要做的事
    public void server(){
        //因为服务器不能关,所以需要写个死循环来监听客户端的链接
        while(true){
            try {
                //监听客户端的链接,客户端链接进来程序才会继续执行
                socket = server.accept();
                System.out.println("客户端:"+socket);
                InputStream is = socket.getInputStream();
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                String re = br.readLine();
                System.out.println(re);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    public static void main(String[] args) {
        //启动服务器
        new ServerDemo().server();
    }
}
服务器端

三、基于UDP协议的网络通信

  同样,我们先了解一下什么是UDP通信吧UDP的英文全名是User Datagram Protocol--用户数据报协议

  它是一个简单的面向数据报的传输层协议        

  既然UDP是用户数据报协议,那么它传输的时候肯定是以报文的形式传输的,同时UDP是一种不需要建立连接的传输

  所以UDP的数据传输速率快,然后UDP会发生数据丢失的情况。并且UDP一次数据传输不能超过64k。

  UDP通信可以用以下图来表示一下。

大致的传输过程如上。

具体的传输流程请看下图

  

如图所示,我们可以得到一个结果,那就是客户端和服务都是公用的。简单来说就是一个程序既可以成为客户端,

也可以成为服务器端,所以没有TCP那样分开写客户端与服务器端,API主要用到的java类是DatagramSocket类与DatagramPacket类。

我们来看一下API对这两个类的描述:

 

------------------------------我是分隔符-------------------------------

 接下来看看这两个类的用法吧。

查看DatagramSocket的构造方法我们可以看到DatagramSocket可以绑定套接字地址和绑定端口。

查看DatagramPacket的构造方法我们可以看到DatagramPacket是能将数据发出和接收的类,在这个类上可以指定发送到指定主机的指定端口号上。

综上所述,端口和ip可以在DatagramPacket上绑定也可以在DatagramSocket上绑定。

废话不多说,先写一个Demo来实现一个简单的文件收发

package com.demo.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Date;

/**
 * UDP客户端
 * @author Administrator
 *
 */
public class UDPClient {
    private DatagramPacket packet = null;
    private DatagramSocket socket = null;
    //客户端程序端口
    private int port = 8888;
    //客户端需发送的数据
    private byte [] b = null;
    //服务器ip
    private InetAddress address = null;
    
    public UDPClient(){
        try {
            socket = new DatagramSocket();
            //将字符串装换成InetAddress类型
            address = InetAddress.getByName("localhost");
            System.out.println("客户端初始化成功");
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    /**
     * 发送数据的方法
     */
    public void send (){
        String date = new Date()+"";
        b = date.getBytes();
        System.out.println(date);
        //将数据打包成一个DatagramPacket报文的格式
        packet=new DatagramPacket(b, b.length, address, port);
        try {
            //以报文的方式发送数据包
            socket.send(packet);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
            
    }
    /**
     * 单报文内的文件发送完了关闭这个Socket通信
     */
    public void close(){
        if(packet!=null){
            socket.close();
        }
    }
    
    public static void main(String[] args) {
        UDPClient udpClient = new UDPClient();
        for(int i =0;i<10;i++){
            udpClient.send();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        udpClient.close();
        
    }
}
package com.demo.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
 * 服务端
 * @author Administrator
 *
 */
public class UDPServer {
    private DatagramSocket socket = null;
    private DatagramPacket packet = null;
    private int port = 8888;
    private byte [] b = null;
    public UDPServer(){
        try {
            socket = new DatagramSocket(port);
            //每次接收的文件大小
            b = new byte[4096];
            System.out.println("服务器初始化成功");
            //创建一个DatagramPacket对象接收的长度为4096字节,接收到b数组中。
            packet = new DatagramPacket(b, b.length);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
    /**
     * 接收方法
     */
    public void resive(){
        try {
            if(!socket.isClosed()){
                socket.receive(packet);
            }
            
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        byte[] data = packet.getData();
        String s = new String(data);
        for(int i =0;i<10;i++){
            System.out.println(s);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    public static void main(String[] args) {
        new UDPServer().resive();
    }
}

通过观察代码我们可以知道UDP通信主要用了这两个方法中的send方法与receive方法。

顾名思义一个是发信息,一个是收信息。而且发送与接收都是以报文的方式进行的。

PS:由于UDP不是建立连接的通信,我们不能保证不会丢包,所以不建议使用UDP传输大文件。

 四、基于TCP/IP建立的协议

   如果计算机网络按TCP/IP协议4层结构划分的话可以分为:应用层、传输层、Internet层、网络接口层

  我们知道TCP、UDP是传输层的协议,在传输层上是应用层。由于TCP通信是基于socket套接字进行通信的,但是由于socket套接字是没有唯一标识的。

所以我们需要有一套规范(协议)。这套协议可以我们自己定义,也可以使用现有的协议。UDP通信是通过发送报文的形式来传输信息的。如果一个

客户端要同时向另一个客户端发送多个报文,并且不同的报文需要对方的客户端做不同的事情,那么我们就需要在报文的头部添加一个唯一识别的信息。

也就是我们所说的协议。同样这套协议也可以是我们自定义的,也可以使用现有的协议。

  目前TCP/IP应用层的协议有:

  TCP:FTP  文件传输协议

     HTTP  超文本传输协议

       TELNET 远程连接协议

       SMTP  邮件发送协议

  UDP:DNS   域名解析协议

     TFTP  简单文件传送协议

  还有许多协议这里就不列举了。

五、总结

  

  在java网络通信这一块,由于能力有限,只能聊到这里了,其实网络通信是非常重要的知识点,如果要细分的话,那绝对不是这么一点点

在网络这一块,所有的计算机都需要遵循这些协议,若不遵循这些网络信息传输协议,那网络将会发生错乱。作为一名开发人员,如果不嫌麻烦

的话,可以自定义一套自己用的通信协议。但是,在实际开发中,为了保证效率,我们一般会使用相对比较成熟的协议来通信。在选择TCP/UDP

通信的时候,我们需要考虑下传输数据的大小,考虑应用的场景。

 

  

原文地址:https://www.cnblogs.com/bananafish/p/9713209.html