码迷,mamicode.com
首页 > 编程语言 > 详细

JAVA Class24

时间:2018-04-27 21:16:39      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:sep   net   1.2   bytes   程序   内容   tor   generated   res   

学习内容:

1.网络通信协议

(1)TCP/IP协议:

TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层

技术分享图片

链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。

网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。

传输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。

应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。

客户端与服务端的三次握手:

第一次握手,客户端向服务器端发出连接请求,等待服务器确认。

第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。

第三次握手,客户端再次向服务器端发送确认信息,确认连接。

优缺点:每次连接都要经过三次握手,速度慢,优势在于可以保证传输数据的完整性。

(2)UDP协议:

UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。

优缺点:数据收发不确认,可能会造成数据的不完整,优势在于速度更快。

(3)IP与端口:

IP版本分为IPV4 IPV6,现阶段用户量最大的是IPV4,IP地址是网络上的客户端的身份标识,而端口是用来访问客户端的应用程序。形象的来说,IP地址就是小区名称,而端口则是门牌号。

(4)JAVA的IP地址封装:

InetAddress类,常用方法:

public class Test {

    public static void main(String[] args) {
        try {
            InetAddress inet = InetAddress.getLocalHost();
            System.out.println(inet.getHostAddress());//本机IP地址
            System.out.println(inet.getHostName());//本机名
            System.out.println(InetAddress.getByName("USER-20180226VT"));//在局域网内,根据主机名获取IP,返回一个InetAddress对象,参数可填主机名或者IP地址
        } catch (Exception e) {
            // TODO: handle exception
        }
        
    }

}

2.UDP协议通信:

收发信息的载体:DatagramPacket,常用构造方法有两个:

new DatagramPacket(byte数组,发送字节长度,InetAddress对象,整型端口号);//用于通过指定IP的指定端口号收发数据

new DatagramPacket(byte数组,发送字节长度);//不指定IP、端口号

常用方法:getAddress() 获取ItnetAddress对象 getPort()获取端口号 getLength()获取数据字节长度 getData()获取数据,返回字节数组

上述方法一般用于接收端,读取发送端的信息

收发信息的对象:DatagramSocket,常用构造方法:

new DatagramSocket() 不指定端口号

new DatagramSocket(整型端口号)  指定端口号

常用方法: send()发送数据 receive()发送数据 close() 关闭

public class UDPSend {

    public static void main(String[] args) throws IOException {
        Scanner s = new Scanner(System.in);
        DatagramSocket dgs = new DatagramSocket();//没指定端口号,JVM自动分配
        InetAddress inet = InetAddress.getByName("192.168.1.255");
        while(true) {
            System.out.println("请输入内容:");
            String mess = s.next();
            byte[] send =mess.getBytes();
            DatagramPacket dgp = new DatagramPacket(send,send.length,inet,8888);
            //注意这里的8888是信息发往的端口,发送用的端口是JVM分配的
            dgs.send(dgp);
        }
        
        //dgs.close();
    }

}

public class UDPReceive {

    public static void main(String[] args) throws IOException {
        DatagramSocket dgs = new DatagramSocket(8888);
        while(true) {
            byte[] receive = new byte[1024*64];
            DatagramPacket dgp = new DatagramPacket(receive,receive.length);
            dgs.receive(dgp);
            String ip = dgp.getAddress().getHostAddress();
            int port = dgp.getPort();
            int length = dgp.getLength();
            byte[]data = dgp.getData();
            String s = new String(data,0,length);
            System.out.printf("发送方地址为:%s 发送方端口号为:%d 数据长度为:%d 数据为:%s \n",ip,port,length,s);
        }
        
    }

}

3.TCP通信

由于TCP协议的三次握手机制,所以严格区分服务端和客户端,通过输出、输出字节流来进行数据收发

(1)服务端

ServerSocket 两种构造方式 无参不指定端口,有参指定端口

服务端无法通过Socket对象获取输入输出流,要通过accept()方法返回一个Socket对象 :Socket s = ss.accept();//返回的是客户端的Socket对象

(2)客户端

Socket 构造器均为有参,new Socket(String host, int port) new Socket(InetAddress address, int port),常用的时第一种

Socket通过getInputStream()、getOutputStream() 获取输入输出流

聊天小程序:

收发线程:

public class SendThread implements Runnable{
         private Socket s;
         public SendThread(Socket s){
            this.s = s;
        }
        public void run(){
            try {
                OutputStream os = s.getOutputStream();
                DataOutputStream dos = new DataOutputStream(os);
                while(true){
                    Scanner sc = new Scanner(System.in);
                    String str = sc.next();
                    dos.writeUTF(str);
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
             
        }
}

public class ReceiveThread implements Runnable{
    private Socket s;
    public ReceiveThread(Socket s) {
        this.s = s;
    }
    public void run() {
        try {
            InputStream is = s.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            String ip = s.getInetAddress().getHostAddress();
            int port = s.getLocalPort();
            while (true) {
                String msg = dis.readUTF();
                System.out.println("来自:"+ip+"端口:"+port+"的消息:\n"+msg);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}

服务端与客户端分别开一个收发线程:

public class TCPClient {

    public static void main(String[] args) {
        try {
            Socket s = new Socket("127.0.0.1",8888);
            SendThread st = new SendThread(s);
            ReceiveThread rt = new ReceiveThread(s);
            new Thread(st).start();
            new Thread(rt).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }

}

public class TCPServer {

    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(8888);
            System.out.println("服务器正在监听8888端口");
            Socket s = ss.accept();//返回的是客户端的Socket对象
            SendThread st = new SendThread(s);
            ReceiveThread rt = new ReceiveThread(s);
            new Thread(st).start();
            new Thread(rt).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

 多线程数据上传:

注意shutdownOutput这个方法,当socket关闭时也会有同样效果,但是在关闭之前,如果再开一个输出流即需要客户端、服务端信息交换,则必须在客户端使用该方法,通知客户端数据传输完毕,同时客户端的输入流也会随之关闭,否则服务端会一直在读取客户端传来的数据,哪怕实际没有数据传输,而客户端的输入流一直在等待服务端传来的数据,导致阻塞!

public class UploadThread implements Runnable{
    private Socket s;
     public UploadThread(Socket s){
        this.s = s;
    }
    public void run(){
        File f = new File("d:\\test\\1366768.jpg");
        try (FileInputStream fis = new FileInputStream(f);
                OutputStream os=s.getOutputStream();
                ){
            byte[] upload = new byte[(int)f.length()];
            fis.read(upload);
            os.write(upload);
            s.shutdownOutput();//关闭上传客户端的输出流,通知服务端客户端的数据传输完毕,服务端的输入流也随之关闭
            InputStream is = s.getInputStream();//不关闭,is在等待读取新的输出流的数据
            byte[] mess = new byte[1024];
            int len=is.read(mess);
            System.out.println(len);
            System.out.println(new String(mess,0,len));
        } catch (IOException e) {
                // TODO Auto-generated catch block
        e.printStackTrace();
        } finally {
            try {
                s.close();//一定要关闭,否则服务端会一直在读取客户端的输出流,导致最终文件没有被上传!
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
public class ServerThread implements Runnable{
    private Socket s;
    public ServerThread(Socket s) {
        this.s = s;
    }
    Object o = new Object();
    public void run() {
        synchronized(o) {
            File f = new File("d:\\upload");
              String file =f.getPath()+File.separator+System.currentTimeMillis()+".jpg";
            try(FileOutputStream fos = new FileOutputStream(file);){
                InputStream is = s.getInputStream();
                byte[] read = new byte[1024];
                int a = 0;
                if(!f.exists()) {
                      f.mkdirs();
                  }
                while((a=is.read(read))!=-1) {
                    System.out.println(a);
                    fos.write(read,0,read.length);
                }
                System.out.println("结束!");
                s.getOutputStream().write("上传成功".getBytes());
//注意这里,因为服务端又新开了一个输出流,导致客户端一定要关闭之前的输出流,与此同时服务端的输入流也随之关闭,
而新增的这个输出流与客户端用来接收这个输出流的输入流会在socket关闭时关闭,如果没有这个输出流,客户端只需最后关闭socket就好!
} catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }

 

JAVA Class24

标签:sep   net   1.2   bytes   程序   内容   tor   generated   res   

原文地址:https://www.cnblogs.com/whwjava/p/8961923.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!