bugstar

导航

23.网络.md

1.基本概念

  • 定义:网络号+主机号。是四个32位的二进制数据,为方便记忆划分为四个8位。
    Demo:

连接特定的 DNS 后缀 . . . . . . . : hollysys.net

本地链接 IPv6 地址. . . . . . . . : fe80::a1e4:76bc:79be:9806%11
IPv4 地址 . . . . . . . . . . . . : 172.21.32.29
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 172.21.32.254

这里的172.21.32三位都是网络号,最后的29是主机号。划分的依据是子网掩码中,255段都表示这是网络号段,最后的0是主机号段。

  • 要素:

    • IP

    • 端口

    • 协议

  • 分类:
    类别 | 内容 | 数量 | 使用范围
    -------|--------------------------------------------------|-----------------
    A类 | 一个网络号+三个主机号 | 2^24个 | 国家使用
    B类 | 两个个网络号+两个个主机号 | 2^12个 | 事业单位使用

    C类 | 三个网络号+一个主机号 | 2^8个 | 私人使用

2.常用函数

package per.liyue.code.net;


import java.net.InetAddress;
import java.net.UnknownHostException;


public class GetIpAddress {
	public static void main(String[] args) throws UnknownHostException{
		//这个类没有构造,所以静态函数获取对象
		InetAddress ip = InetAddress.getLocalHost();
		//获取ip地址
		System.out.println("我的Ip地址:" + ip.getHostAddress());
		//获取机器名
		System.out.println("我的Ip机器名:" + ip.getHostName());
		
		//获取其他机器的IP信息-getByName既可以填出机器名,也可以填充IP
		String otherIp = "172.21.32.20";
		String nameIp = "AMS97-PC";
		InetAddress getIP = InetAddress.getByName(otherIp);
		System.out.println("目标机器的IP是:" + getIP.getHostName());
		InetAddress getName = InetAddress.getByName(nameIp);
		System.out.println("目标机器的IP是:" + getName.getHostAddress());
		
		//可以用于获取某个域名下的IP
		InetAddress[] a = InetAddress.getAllByName("www.hollysys.com");
		for (InetAddress inetAddress : a) {
			System.out.println("net:" + inetAddress.getHostAddress());
		}
	}
}

3.端口

  • 端口范围:0~65535,其中
    • 0~1023:系统端口:系统紧密绑定

    • 1024~49151:注册端口:系统松散绑定

    • 1024~65535:可用,如果出错则换另一个

4.协议

不同的协议对应不同的Scoket:
*
*

4.1UDP

4.1.1特点

  • 不需要建立连接
  • 每包大小64K
  • 速度快,非可靠(丢包)
  • 不区分客户端服务端,之区分发送端和接收端

4.1.2代码步骤

步骤

  • 发送端:

    • 建立服务DatagramSocket()

    • 创建数据包public DatagramPacket(byte buf[], int length,

                      InetAddress address, int port)    * 发送数据DatagramSocket.send()
      
    • 关闭资源

  • 接收端:

    • 建立服务绑定端口:public DatagramSocket(int port)

    • 创建数据包接收:public DatagramPacket(byte buf[], int length)

    • 用阻塞方法接收数据:DatagramSocket.receive()

    • 关闭资源

4.1.3UDPDemo

Demo:

package per.liyue.code.udptest;
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.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
/*
 * Udp发送类,用于发送数据
 */
public class UdpSender {
    public static void main(String[] args) throws IOException {
        //建立socket
        DatagramSocket socketSend = new DatagramSocket();
        
        //创建数据包
        String sendConcent = "这是我发送的一包数据";
        /*
         * 这里使用DatagramPacket来存放发送数据,使用的构造是:
         * public DatagramPacket(byte buf[],         //缓冲数组存放发送数据
         *                          int length,         //要用缓冲数组的长度
         *                          InetAddress address,//目标IP地址
         *                          int port            //目标端口
         *                         )
         * 
         * */
        DatagramPacket packetSend = new DatagramPacket(sendConcent.getBytes(), sendConcent.getBytes().length, InetAddress.getLocalHost(), 10001);
        
        //发送数据
        socketSend.send(packetSend);
        socketSend.close();
        System.out.println("数据已经发送,时间:" + new SimpleDateFormat("yyyy-MM-DD HH-mm-ss").format(new Date()));
    }
}
package per.liyue.code.udptest;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
 * Udp接收数据类,用于接收数据
 */
public class UdpReceive {
    public static void main(String[] args) throws IOException {
        //建立socket
        DatagramSocket socketReceive = new DatagramSocket(10001);
        
        System.out.println("接收端开启监听...");
        
        //数据包接收
        byte[] bufRecive = new byte[1024];
        /*
         * 用DatagramPacket来接收数组,这里要用构造:
         * public DatagramPacket(byte buf[], //缓冲数组来接收,数据实际存放于数组中
         *                          int length) //缓冲数组长度    
         */
        DatagramPacket packetReceive = new DatagramPacket(bufRecive, bufRecive.length);
        
        //这个方法是阻塞的:This method blocks until a datagram is received。收到数据才执行
        socketReceive.receive(packetReceive);
        socketSend.close();
        //要注意的是
        System.out.println("接收到数据:" + new String(bufRecive, 0, packetReceive.getLength()));
        System.out.println("接收时间:" + new SimpleDateFormat("yyyy-MM-DD HH-mm-ss").format(new Date()));
        
    }
}

4.1.4通信格式

一般的通信中,数据内容有规定的格式,否则当垃圾数据处理,例如飞秋的为:

version:time:sender:ip:flag:concnet

  • 这里的版本号强制使用1.0
  • 时间使用系统时间
  • 发送人随意
  • ip是给对方显示地址
  • flag强制为32
  • concent是真正的内容
package per.liyue.code.udptest;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class UdpSendFeiQ {
    public static void main(String[] args) throws IOException {
        DatagramSocket send = new DatagramSocket();
        
        String concent = getconcent("飞啊飞");
        System.out.println("发送内容: " + concent);
        DatagramPacket packet = new DatagramPacket(concent.getBytes(), concent.getBytes().length,
                                                   InetAddress.getByName("172.21.32.20"), 2425);
        send.send(packet);
        send.close();
    }
    /*
     * 飞秋的数据格式:version:time:sender:ip:flag:concnet
     *                 1.0                    32
     */
    
    public static String getconcent(String concent) {
        StringBuilder builder = new StringBuilder();
        builder.append("1.0:");
        builder.append(System.currentTimeMillis() + ":");
        builder.append("172.21.32.30:");
        builder.append("超人:");
        builder.append("32:");
        builder.append(concent);
        return builder.toString();
    }
}

广播地址:在UDP中将主机号修改为255就是网络广播地址,会群发。例如飞秋的地址为:

172.21.32.255

4.1.5 群发Demo:

package per.liyue.code.udptest;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.Runnable;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;


public class ChatSender implements Runnable {
	@Override
	public void run() {
		try {
			//
			DatagramSocket send = new DatagramSocket();
			
			//
			BufferedReader read = new BufferedReader(
									new InputStreamReader(System.in));
			String line = null;
			DatagramPacket packet = null;
			while((line = read.readLine()) != null){
				packet = new DatagramPacket(line.getBytes(), line.getBytes().length,
											InetAddress.getLocalHost(), 10001);
				send.send(packet);
			}
			send.close();
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
}


package per.liyue.code.udptest;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class ChatReceive implements Runnable {
    @Override
    public void run() {
        try {
            // TODO Auto-generated method stub
            DatagramSocket socket = new DatagramSocket(10001);
            byte[] concent = new byte[1024];
            DatagramPacket packet = new DatagramPacket(concent, concent.length);
            
            boolean flag = true;
            while (flag) {
                socket.receive(packet);
                System.out.println(
                        packet.getAddress().getHostName() + "说:" + 
                        new String(concent, 0, concent.length));
            }
            socket.close();
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
package per.liyue.code.udptest;
public class ChatMain {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ChatReceive receive = new ChatReceive();
        ChatSender send = new ChatSender();
        new Thread(receive).start();
        new Thread(send).start();
    }
}

4.1.6丢失数据的情况

  • 带宽不够
  • cpu处理能力不足

目录


4.2TCP

  • 面向连接:建立连接
  • 大数据,数据传输时候没有大小限制
  • 效率相对低:三次握手机制,可靠
  • 区分客户端服务的

4.2.1三次握手机制

发送数据之前要检查通路是否正常,所以是可靠连接。

4.2.2通信范例

  • 客户端:发送命令方-》Socket类
  • 服务端:接收命令方-》ServerSocket类

4.2.2.1单次通信

Demo:
单次建立连接通信:

package per.liyue.code.tcptest;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
    public static void main(String[] args) throws UnknownHostException, IOException {
        //建立socket链接,指定IP和端口号
        Socket socket = new Socket(InetAddress.getLocalHost(), 10001);
        //获取到输出流
        OutputStream out = socket.getOutputStream();
        
        String conent = "我是客户端,向服务端发送数据了!";
        //这里用输出流的写方法发送
        out.write(conent.getBytes());
        //关闭资源,输出流是从Socket中获取,所以关闭Socket就可以了
        socket.close();
    }
}
package per.liyue.code.tcptest;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
    public static void main(String[] args) throws IOException {
        //建立服务端监听端口
        ServerSocket sSocket = new ServerSocket(10001);
        
        //accept方法本身也是阻塞的方法
        Socket socket = sSocket.accept();
        //因为ServerSocket本身没有流对象的获取,所以要从Socket中获取,客户端发送的时候已经将流发送
        
        InputStream in = socket.getInputStream();
        
        byte[] b = new byte[1024];
        int length = in.read(b);
        //打印接收内容
        System.out.println("服务器接收到的数据:" + new String(b, 0, length));
        //关闭资源,输入流和Socket都是通过ServerSocket获取,所以关闭一个即可
        sSocket.close();
    }
}

注意:为什么不对ServerSocket提供getInputStream和getOutputStream,因为如果ServerSocket本身有提供,在多客户端连接时候,服务端回复的话一个输入输出不能辨别出回复到哪个客户端。所以设计了Socket提供。

4.2.2.2持久化通信

Demo:

package per.liyue.code.tcptest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import com.sun.imageio.plugins.common.InputStreamAdapter;
/*
 * TCp实现客户端和服务器互相通信
 */
public class ClientChat {
    public static void main(String[] args) {
        try {
            System.out.println("客户端已经打开,准备发送...");
            
            //创建
            Socket socket = new Socket(InetAddress.getLocalHost(), 10001);
            
            OutputStream out = socket.getOutputStream();
            //将字符流转换为字节流方便传输
            OutputStreamWriter send = new OutputStreamWriter(out);
            
            //获取键盘输入流,将输入的字节流转化为字符流
            InputStreamReader in =  new InputStreamReader(System.in);
            BufferedReader bufRead = new BufferedReader(in);
            
            String line = null;
            while((line=bufRead.readLine()) != null){
                /*
                 * 将输入的内容发送
                 * 注意:因为接收的时候也以readLine来接收,这个方法以回车换行来判断,
                 *       但是这里的获取输入并不会增加换行回车,所以得手动增加
                 */
                send.write(line + "\r\n");
                //这里不能忘记刷新,否则内容只存在于缓存数组中
                send.flush()  
            }
            socket.close();
            
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
    }
}
package per.liyue.code.tcptest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerChat {
    public static void main(String[] args) {
        
        try {
            System.out.println("服务端已经打开,等待接收...");
            
            //创建ServerSocket
            ServerSocket sSocket = new ServerSocket(10001);
            //获取Socket对象
            Socket socket = sSocket.accept();
            //获取输入流
            InputStream in =  socket.getInputStream();
            InputStreamReader inRead = new InputStreamReader(in);
            
            //将收到的字节流转换为字符流方便输出
            BufferedReader read = new BufferedReader(inRead);
            
            String line = null;
            while ((line = read.readLine()) != null) {
                System.out.println("服务端收到:" + line);
            }
            sSocket.close();  
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
}

4.2.2.3持久化相互通信

Demo:

package per.liyue.code.tcptest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import com.sun.imageio.plugins.common.InputStreamAdapter;
/*
 * TCp实现客户端和服务器互相通信
 */
public class ClientChat {
    public static void main(String[] args) {
        try {
            System.out.println("客户端已经打开,准备发送...");
            /*
             * 输出流准备
             */
            //创建
            Socket socket = new Socket(InetAddress.getLocalHost(), 10001);
            
            OutputStream out = socket.getOutputStream();
            //将字符流转换为字节流方便传输
            OutputStreamWriter send = new OutputStreamWriter(out);
            
            //获取键盘输入流,将输入的字节流转化为字符流
            InputStreamReader in =  new InputStreamReader(System.in);
            BufferedReader bufRead = new BufferedReader(in);
            
            String line = null;
            
            /*
             * 输入准备
             */
            //获取输入流
            //获取输入内容
            BufferedReader readFormServer = new BufferedReader(
                                    new InputStreamReader(socket.getInputStream())
                                                     );
            
            while((line=bufRead.readLine()) != null){
                /*
                 * 将输入的内容发送
                 * 注意:因为接收的时候也以readLine来接收,这个方法以回车换行来判断,
                 *       但是这里的获取输入并不会增加换行回车,所以得手动增加
                 */
                send.write(line + "\r\n");
                //这里不能忘记刷新,否则内容只存在于缓存数组中
                send.flush();
                
                //收到服务端
                String lineRead = readFormServer.readLine();
                System.out.println("客户端收到:" + lineRead);    
            }
            socket.close();
            
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
    }
}
package per.liyue.code.tcptest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerChat {
    public static void main(String[] args) {
        
        try {
            System.out.println("服务端已经打开,等待接收...");
            
            /*
             * 获取输入准备
             */
            //创建ServerSocket
            ServerSocket sSocket = new ServerSocket(10001);
            //获取Socket对象
            Socket socket = sSocket.accept();
            //获取输入流
            InputStream in =  socket.getInputStream();
            InputStreamReader inRead = new InputStreamReader(in);
            
            //将收到的字节流转换为字符流方便输出
            BufferedReader read = new BufferedReader(inRead);
            
            String line = null;            
            /*
             * 输出准备
             */
            //获取输出流
            OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
            //获取准备输出的数据
            BufferedReader write = new BufferedReader(new InputStreamReader(System.in));
            
            while ((line = read.readLine()) != null) {
                System.out.println("服务端收到:" + line);
                
                String lineWrite = write.readLine();
                out.write("服务端说:" + lineWrite + "\r\n");
                out.flush();
            }
            sSocket.close();
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
}

posted on 2018-03-02 13:51  bugstar  阅读(189)  评论(0)    收藏  举报