zoukankan      html  css  js  c++  java
  • java基础学习_网络编程_day26总结

    java基础学习_网络编程_day26总结

    =============================================================================
    =============================================================================
    涉及到的知识点有:
    1:网络编程(理解)
        (1)网络编程的概述
        (2)网络参考模型
        (3)网络通信的三要素
            A:IP地址
            B:端口
            C:通信协议
        (4)Socket机制
        (5)UDP协议发送和接收数据(掌握)
        (6)TCP协议发送和接收数据(掌握)
        (7)案例:
            A:UDP
                a:最基本的UDP协议发送和接收数据
                b:把发送数据改进为键盘录入
                c:一个简易聊天小程序并用多线程改进
            B:TCP
                a:最基本的TCP协议发送和接收数据
                b:服务器给出反馈
                c:客户端键盘录入,服务器输出控制台(字符流)
                d:客户端键盘录入,服务器写到文本文件(字符流)
                e:客户端读取文本文件,服务器写到文本文件/输出控制台(字符流)
                f:上传图片(字节流)
                    注意:在通道字节流中要使用flush()刷新方法。否则数据会有丢失。
                g:多线程改进上传文件
    =============================================================================
    =============================================================================
    1:网络编程(理解)
        (1)网络编程的概述
            网络编程:用Java语言实现计算机间数据的信息传递资源共享(2)网络参考模型
            OSI参考模型(Open System Interconnection:开放系统互连)
            TCP/IP参考模型

    -------------------------------------- (3)网络通信的三要素 A:IP地址 a:点分十进制 b:IP地址的组成 c:IP地址的分类 d:两个DOS命令 e:InetAddress类(为了方便我们对IP地址的获取和操作,java提供了一个类InetAddress供我们使用) InetAddress类的成员方法:(注意该类中没有构造方法) public static InetAddress getByName(String host) 根据主机名或者IP地址的字符串表示得到IP地址对象 B:端口 每个程序都会至少有一个逻辑端口。 是应用程序的标识。 范围:0-65535。其中0-1024不建议使用。 C:通信协议 UDP:数据打包,有限制,不连接,效率高,不可靠。 TCP:建立数据通道,无限制,效率低,可靠。 -------------------------------------- (4)Socket机制 A:通信两端都有Socket对象。 B:所有的通信都是通过Socket间的IO进行操作的。 C:网络通信其实就是Socket间的通信。
    -------------------------------------- (5)UDP协议发送和接收数据(掌握) 发送: A:创建发送端Socket对象(DatagramSocket) B:创建数据,并把数据打包(DatagramPacket) C:调用Socket对象的发送方法发送数据报包 D:释放资源 接收: A:创建接收端Socket对象,并指定端口号(DatagramSocket) B:创建一个数据包(接收容器)(DatagramPacket) C:调用Socket对象的接收方法接收数据 D:解析数据包,并显示在控制台 E:释放资源 Exception in thread "main" java.net.BindException: Address already in use: Cannot bind 多次启动接收端出现异常端口被占用
    -------------------------------------- (6)TCP协议发送和接收数据(掌握) 发送: A:创建发送端Socket对象,并明确要连接的服务器(Socket) A步骤如果创建对象成功,就说明连接通道已建立成功了。 B:调用Socket对象获取输出流对象,写数据(OutputStream) C:释放资源 接收: A:创建接收端Socket对象,并指定端口(ServerSocket) B:监听客户端连接,返回一个对应的Socket对象 C:获取输入流对象,读取数据显示在控制台(InputStream) D:释放资源 Exception in thread "main" java.net.ConnectException: Connection refused: connect 连接被拒绝。TCP协议一定要先开服务器。 因为TCP保证数据一定被收到,所以接收端一定要先开启。
    -------------------------------------- (7)案例: A:UDP a:最基本的UDP协议发送和接收数据
    基本版本:
     1 package cn.itcast_02;
     2 
     3 import java.io.IOException;
     4 import java.net.DatagramPacket;
     5 import java.net.DatagramSocket;
     6 import java.net.InetAddress;
     7 /*
     8  * UDP协议发送数据:
     9  *         A:创建发送端Socket对象(DatagramSocket)
    10  *         B:创建数据,并把数据打包(DatagramPacket)
    11  *         C:调用Socket对象的发送方法发送数据报包
    12  *         D:释放资源
    13  * 
    14  * DatagramSocket类:数据报套接字类,此类表示用来发送和接收数据报包的套接字。 
    15  */
    16 public class SendDemo {
    17     public static void main(String[] args) throws IOException {
    18         // 创建发送端Socket对象(DatagramSocket)
    19         // DatagramSocket类的构造方法:public DatagramSocket()
    20         DatagramSocket ds = new DatagramSocket();
    21 
    22         // 创建数据,并把数据打包(DatagramPacket)
    23         // DatagramPacket类的构造方法:public DatagramPacket(byte[] buf, int length, InetAddress address, int port)
    24         // 创建数据
    25         byte[] bys = "hello,UDP,我来了".getBytes(); // 把字符串转为字符数组
    26         // 长度
    27         int length = bys.length;
    28         // 获取IP地址对象
    29         InetAddress address = InetAddress.getByName("192.168.40.9");
    30         // 端口
    31         int port = 10086;
    32         DatagramPacket dp = new DatagramPacket(bys, length, address, port);
    33 
    34         // 调用Socket对象的发送方法发送数据报包
    35         // DatagramSocket类的成员方法:public void send(DatagramPacket p) 发送数据报包
    36         ds.send(dp);
    37 
    38         // 释放资源
    39         ds.close();
    40     }
    41 }
    SendDemo.java
     1 package cn.itcast_02;
     2 
     3 import java.io.IOException;
     4 import java.net.DatagramPacket;
     5 import java.net.DatagramSocket;
     6 import java.net.InetAddress;
     7 
     8 /*
     9  * UDP协议接收数据:
    10  *         A:创建接收端Socket对象,并指定端口号(DatagramSocket)
    11  *         B:创建一个数据包(接收容器)(DatagramPacket)
    12  *         C:调用Socket对象的接收方法接收数据
    13  *         D:解析数据包,并显示在控制台
    14  *         E:释放资源
    15  */
    16 public class ReceiveDemo {
    17     public static void main(String[] args) throws IOException {
    18         // 创建接收端Socket对象,并指定端口号(DatagramSocket)
    19         // DatagramSocket类的构造方法:public DatagramSocket(int port)
    20         DatagramSocket ds = new DatagramSocket(10086);
    21 
    22         // 创建一个数据包(接收容器)(DatagramPacket)
    23         // DatagramPacket类的构造方法:public DatagramPacket(byte[] buf, int length)
    24         byte[] bys = new byte[1024];
    25         int length = bys.length;
    26         DatagramPacket dp = new DatagramPacket(bys, length);
    27 
    28         // 调用Socket对象的接收方法接收数据
    29         // DatagramSocket类的成员方法:public void receive(DatagramPacket p) 接收数据报包,当此方法返回时,DatagramPacket的缓冲区里填充了接收的数据,数据报包也包含发送方的IP地址和发送方机器上的端口号。
    30         ds.receive(dp); // 阻塞式(此方法在接收到数据报前一直阻塞)
    31 
    32         // 解析数据包,并显示在控制台
    33         // DatagramPacket类的成员方法:public InetAddress getAddress() // 获取IP地址(此时为发送端的IP地址)
    34         InetAddress address = dp.getAddress();
    35         String ip = address.getHostAddress();
    36         // DatagramPacket类的成员方法:public byte[] getData() 获取数据缓冲区
    37         // DatagramPacket类的成员方法:public int getLength() 获取数据的实际长度
    38         byte[] bys2 = dp.getData();
    39         int len = dp.getLength();
    40         String s = new String(bys2, 0, len);
    41         System.out.println(ip + "传递的数据是:" + s);
    42 
    43         // 释放资源
    44         ds.close();
    45     }
    46 }
    ReceiveDemo.java
    改进版本:(使用链式编程)
     1 package cn.itcast_03;
     2 
     3 import java.io.IOException;
     4 import java.net.DatagramPacket;
     5 import java.net.DatagramSocket;
     6 import java.net.InetAddress;
     7 /*
     8  * UDP协议发送数据:
     9  *         A:创建发送端Socket对象(DatagramSocket)
    10  *         B:创建数据,并把数据打包(DatagramPacket)
    11  *         C:调用Socket对象的发送方法发送数据报包
    12  *         D:释放资源
    13  * 
    14  * DatagramSocket类:数据报套接字类,此类表示用来发送和接收数据报包的套接字。 
    15  */
    16 public class SendDemo {
    17     public static void main(String[] args) throws IOException {
    18         // 创建发送端Socket对象(DatagramSocket)
    19         DatagramSocket ds = new DatagramSocket();
    20 
    21         // 创建数据,并把数据打包(DatagramPacket)
    22         byte[] bys = "hello,UDP,我来了".getBytes(); // 把字符串转为字符数组
    23         DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("192.168.40.9"), 10086);
    24 
    25         // 调用Socket对象的发送方法发送数据报包
    26         ds.send(dp);
    27 
    28         // 释放资源
    29         ds.close();
    30     }
    31 }
    SendDemo.java
     1 package cn.itcast_03;
     2 
     3 import java.io.IOException;
     4 import java.net.DatagramPacket;
     5 import java.net.DatagramSocket;
     6 
     7 /*
     8  * UDP协议接收数据:
     9  *         A:创建接收端Socket对象,并指定端口号(DatagramSocket)
    10  *         B:创建一个数据包(接收容器)(DatagramPacket)
    11  *         C:调用Socket对象的接收方法接收数据
    12  *         D:解析数据包,并显示在控制台
    13  *         E:释放资源
    14  * 
    15  * Exception in thread "main" java.net.BindException: Address already in use: Cannot bind
    16  *         多次启动接收端出现异常。端口被占用。
    17  */
    18 public class ReceiveDemo {
    19     public static void main(String[] args) throws IOException {
    20         // 创建接收端Socket对象,并指定端口号(DatagramSocket)
    21         DatagramSocket ds = new DatagramSocket(10086);
    22 
    23         // 创建一个数据包(接收容器)(DatagramPacket)
    24         byte[] bys = new byte[1024];
    25         DatagramPacket dp = new DatagramPacket(bys, bys.length);
    26 
    27         // 调用Socket对象的接收方法接收数据
    28         ds.receive(dp); // 阻塞式(此方法在接收到数据报前一直阻塞)
    29 
    30         // 解析数据包,并显示在控制台
    31         String ip = dp.getAddress().getHostAddress();
    32         String s = new String(dp.getData(), 0, dp.getLength());
    33         System.out.println(ip + "传递的数据是:" + s);
    34 
    35         // 释放资源
    36         ds.close();
    37     }
    38 }
    ReceiveDemo.java
                b:把发送数据改进为键盘录入
     1 package cn.itcast_04;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.IOException;
     5 import java.io.InputStreamReader;
     6 import java.net.DatagramPacket;
     7 import java.net.DatagramSocket;
     8 import java.net.InetAddress;
     9 /*
    10  * UDP案例:
    11  *         从键盘录入数据进行发送,如果输入的是886那么客户端就结束输入数据。 
    12  * 
    13  *         数据来自于键盘录入,键盘录入数据要自己控制录入结束。
    14  */
    15 public class SendDemo {
    16     public static void main(String[] args) throws IOException {
    17         // 创建发送端Socket对象
    18         DatagramSocket ds = new DatagramSocket();
    19         
    20         // 封装键盘录入数据对象
    21         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    22         String line = null;
    23         while ((line = br.readLine()) != null) {
    24             if ("886".equals(line)) {
    25                 break;
    26             }
    27             
    28             // 创建数据,并把数据打包
    29             byte[] bys = line.getBytes();
    30             // DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("192.168.40.9"), 10086);
    31             DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("192.168.40.255"), 10086); // 广播地址
    32 
    33             // 调用Socket对象的发送方法发送数据报包
    34             ds.send(dp);
    35         }
    36 
    37         // 释放资源
    38         ds.close();
    39     }
    40 }
    SendDemo.java
     1 package cn.itcast_04;
     2 
     3 import java.io.IOException;
     4 import java.net.DatagramPacket;
     5 import java.net.DatagramSocket;
     6 
     7 /*
     8  * UDP案例:
     9  *         从键盘录入数据进行发送,如果输入的是886那么客户端就结束输入数据。 
    10  */
    11 public class ReceiveDemo {
    12     public static void main(String[] args) throws IOException {
    13         // 创建接收端Socket对象,并指定端口号
    14         DatagramSocket ds = new DatagramSocket(10086);
    15 
    16         while (true) {
    17             // 创建一个数据包(接收容器)
    18             byte[] bys = new byte[1024];
    19             DatagramPacket dp = new DatagramPacket(bys, bys.length);
    20     
    21             // 调用Socket对象的接收方法接收数据
    22             ds.receive(dp); // 阻塞式(此方法在接收到数据报前一直阻塞)
    23     
    24             // 解析数据包,并显示在控制台
    25             String ip = dp.getAddress().getHostAddress();
    26             String s = new String(dp.getData(), 0, dp.getLength());
    27             System.out.println(ip + "传递的数据是:" + s);
    28         }
    29         
    30         // 释放资源
    31         // ds.close(); // 接收端应该一直开着等待接收数据,是不需要关闭的。
    32     }
    33 }
    ReceiveDemo.java
                c:一个简易聊天小程序并用多线程改进
     1 package cn.itcast_05;
     2 
     3 import java.io.IOException;
     4 import java.net.DatagramSocket;
     5 
     6 /*
     7  * 通过多线程改进刚才的聊天程序,这样我就可以实现在一个窗口发送和接收数据了
     8  */
     9 public class ChatRoom {
    10     public static void main(String[] args) throws IOException {
    11         DatagramSocket dsSend = new DatagramSocket();
    12         DatagramSocket dsReceive = new DatagramSocket(10086);
    13 
    14         SendThread st = new SendThread(dsSend);
    15         ReceiveThread rt = new ReceiveThread(dsReceive);
    16 
    17         Thread t1 = new Thread(st);
    18         Thread t2 = new Thread(rt);
    19 
    20         t1.start();
    21         t2.start();
    22     }
    23 }
    ChatRoom.java
     1 package cn.itcast_05;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.IOException;
     5 import java.io.InputStreamReader;
     6 import java.net.DatagramPacket;
     7 import java.net.DatagramSocket;
     8 import java.net.InetAddress;
     9 
    10 public class SendThread implements Runnable {
    11 
    12     private DatagramSocket ds;
    13 
    14     public SendThread(DatagramSocket ds) {
    15         this.ds = ds;
    16     }
    17 
    18     @Override
    19     public void run() {
    20         try {
    21             // 封装键盘录入数据对象
    22             BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    23             String line = null;
    24             while ((line = br.readLine()) != null) {
    25                 if ("886".equals(line)) {
    26                     break;
    27                 }
    28 
    29                 // 创建数据,并把数据打包
    30                 byte[] bys = line.getBytes();
    31                 DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("192.168.40.9"), 10086);
    32 
    33                 // 调用Socket对象的发送方法发送数据报包
    34                 ds.send(dp);
    35             }
    36             // 释放资源
    37             ds.close();
    38         } catch (IOException e) {
    39             e.printStackTrace();
    40         }
    41     }
    42 
    43 }
    SendThread.java
     1 package cn.itcast_05;
     2 
     3 import java.io.IOException;
     4 import java.net.DatagramPacket;
     5 import java.net.DatagramSocket;
     6 
     7 public class ReceiveThread implements Runnable {
     8     
     9     private DatagramSocket ds;
    10 
    11     public ReceiveThread(DatagramSocket ds) {
    12         this.ds = ds;
    13     }
    14 
    15     @Override
    16     public void run() {
    17         try {
    18             while (true) {
    19                 // 创建一个数据包(接收容器)
    20                 byte[] bys = new byte[1024];
    21                 DatagramPacket dp = new DatagramPacket(bys, bys.length);
    22 
    23                 // 调用Socket对象的接收方法接收数据
    24                 ds.receive(dp);
    25 
    26                 // 解析数据包,并显示在控制台
    27                 String ip = dp.getAddress().getHostAddress();
    28                 String s = new String(dp.getData(), 0, dp.getLength());
    29                 System.out.println("from " + ip + " data is : " + s);
    30             }
    31         } catch (IOException e) {
    32             e.printStackTrace();
    33         }
    34     }
    35 
    36 }
    ReceiveThread.java
            B:TCP
                a:最基本的TCP协议发送和接收数据
                b:服务器给出反馈
                c:客户端键盘录入,服务器输出控制台(字符流)
                d:客户端键盘录入,服务器写到文本文件(字符流)
     1 package cn.itcast_09;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.BufferedWriter;
     5 import java.io.IOException;
     6 import java.io.InputStreamReader;
     7 import java.io.OutputStreamWriter;
     8 import java.net.Socket;
     9 
    10 /*
    11  * 客户端键盘录入,服务器写到文本文件
    12  */
    13 public class ClientDemo {
    14     public static void main(String[] args) throws IOException {
    15         // 创建客户端Socket对象
    16         Socket s = new Socket("192.168.40.9", 2222);
    17 
    18         // 包装键盘录入数据对象
    19         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    20         
    21         // 包装通道内的流对象
    22         BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    23 
    24         String line = null;
    25         while ((line = br.readLine()) != null) {
    26             // 键盘录入数据要自定义结束标记
    27             if ("886".equals(line)) {
    28                 break;
    29             }
    30             bw.write(line);
    31             bw.newLine();
    32             bw.flush();
    33         }
    34 
    35         // 释放资源
    36         // bw.close(); // 已经不录入了,关不关流无所谓了
    37         // br.close(); // 本质关闭的是s对象
    38         s.close();
    39     }
    40 }
    ClientDemo.java
     1 package cn.itcast_09;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.BufferedWriter;
     5 import java.io.FileWriter;
     6 import java.io.IOException;
     7 import java.io.InputStreamReader;
     8 import java.net.ServerSocket;
     9 import java.net.Socket;
    10 /*
    11  * 客户端键盘录入,服务器写到文本文件
    12  */
    13 public class ServerDemo {
    14     public static void main(String[] args) throws IOException {
    15         // 创建服务器Socket对象
    16         ServerSocket ss = new ServerSocket(2222);
    17 
    18         // 监听客户端连接
    19         Socket s = ss.accept();
    20 
    21         // 包装通道内的流对象
    22         BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    23         
    24         // 封装文本文件对象
    25         BufferedWriter bw = new BufferedWriter(new FileWriter("src//cn//itcast_09//b.txt"));
    26         
    27         String line = null;
    28         while ((line = br.readLine()) != null) {
    29             bw.write(line);
    30             bw.newLine();
    31             bw.flush();
    32         }
    33 
    34         s.close();
    35         bw.close();
    36     }
    37 }
    ServerDemo.java
                e:客户端读取文本文件,服务器写到文本文件/输出控制台(字符流)
     1 package cn.itcast_10;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.BufferedWriter;
     5 import java.io.FileReader;
     6 import java.io.IOException;
     7 import java.io.OutputStreamWriter;
     8 import java.net.Socket;
     9 
    10 /*
    11  * 客户端读取文本文件,服务器写到文本文件/输出到控制台
    12  */
    13 public class ClientDemo {
    14     public static void main(String[] args) throws IOException {
    15         // 创建客户端Socket对象
    16         Socket s = new Socket("192.168.40.9", 2222);
    17 
    18         // 封装文本文件对象
    19         BufferedReader br = new BufferedReader(new FileReader("src//cn//itcast_10//a.txt"));
    20         
    21         // 包装通道内的流对象
    22         BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    23 
    24         String line = null;
    25         while ((line = br.readLine()) != null) {
    26             bw.write(line);
    27             bw.newLine();
    28             bw.flush();
    29         }
    30 
    31         br.close();
    32         s.close();
    33     }
    34 }
    ClientDemo.java
     1 package cn.itcast_10;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.BufferedWriter;
     5 import java.io.FileWriter;
     6 import java.io.IOException;
     7 import java.io.InputStreamReader;
     8 import java.net.ServerSocket;
     9 import java.net.Socket;
    10 /*
    11  * 客户端读取文本文件,服务器写到文本文件/输出到控制台
    12  */
    13 public class ServerDemo {
    14     public static void main(String[] args) throws IOException {
    15         // 创建服务器Socket对象
    16         ServerSocket ss = new ServerSocket(2222);
    17 
    18         // 监听客户端连接
    19         Socket s = ss.accept();
    20 
    21         // 包装通道内的流对象
    22         BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    23         
    24         // 封装文本文件对象
    25         BufferedWriter bw = new BufferedWriter(new FileWriter("src//cn//itcast_10//Copy.txt"));
    26         
    27         String line = null;
    28         while ((line = br.readLine()) != null) {
    29             bw.write(line);
    30             bw.newLine();
    31             bw.flush();
    32             
    33             System.out.println(line);
    34         }
    35 
    36         s.close();
    37         bw.close();
    38     }
    39 }
    ServerDemo.java
    服务器给出反馈的代码:
     1 package cn.itcast_12;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.BufferedWriter;
     5 import java.io.FileReader;
     6 import java.io.IOException;
     7 import java.io.InputStreamReader;
     8 import java.io.OutputStreamWriter;
     9 import java.net.Socket;
    10 
    11 /*
    12  * 按照我们正常的思路加入反馈信息,结果却没反应。为什么呢?
    13  *         读取文本文件是以null作为结束信息的,但是呢,在通道里读数据,通道内并不是这样结束信息的。
    14  *         所以,服务器根本就不知道你结束了。而客户端还想服务器给反馈。所以,就相互等待了。
    15  * 
    16  * 如何解决呢?
    17  *         A:客户端写完数据后,再写一条数据作为结束标记,服务器读取到这条数据说明客户端结束了,所以服务器该结束了。
    18  *             这样做可以解决问题,但是不好。
    19  *             如果自定义的结束标记与文件的内容相同的话,文件发送就提前结束了。
    20  *         B:Socket对象提供了一种解决方案
    21  *                 public void shutdownOutput()
    22  */
    23 
    24 public class UploadClient {
    25     public static void main(String[] args) throws IOException {
    26         // 创建客户端Socket对象
    27         Socket s = new Socket("192.168.40.9", 11111);
    28 
    29         // 封装文本文件对象
    30         BufferedReader br = new BufferedReader(new FileReader("src//cn//itcast_12//a.txt"));
    31         
    32         // 封装通道内流对象
    33         BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    34 
    35         String line = null;
    36         while ((line = br.readLine()) != null) { // 阻塞
    37             // 在文件里读数据,文件末尾是null!
    38             bw.write(line);
    39             bw.newLine();
    40             bw.flush();
    41         }
    42         
    43         // 自定义一个结束标记
    44         // bw.write("over");
    45         // bw.newLine();
    46         // bw.flush();
    47         
    48         // Socket类提供了一个终止方法,该方法会通知服务器你别等了,我没有数据过来了
    49         s.shutdownOutput();
    50 
    51         // 客户端接收服务器反馈
    52         BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
    53         String client = brClient.readLine(); // 阻塞
    54         System.out.println(client);
    55 
    56         // 释放资源
    57         br.close();
    58         s.close();
    59     }
    60 }
    UploadClient.java
     1 package cn.itcast_12;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.BufferedWriter;
     5 import java.io.FileWriter;
     6 import java.io.IOException;
     7 import java.io.InputStreamReader;
     8 import java.io.OutputStreamWriter;
     9 import java.net.ServerSocket;
    10 import java.net.Socket;
    11 
    12 public class UploadServer {
    13     public static void main(String[] args) throws IOException {
    14         // 创建服务器端Socket对象
    15         ServerSocket ss = new ServerSocket(11111);
    16 
    17         // 监听客户端连接
    18         Socket s = ss.accept(); // 阻塞
    19 
    20         // 封装通道内的流对象
    21         BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    22         
    23         // 封装文本文件对象
    24         BufferedWriter bw = new BufferedWriter(new FileWriter("src//cn//itcast_12//Copy.txt"));
    25 
    26         String line = null;
    27         while ((line = br.readLine()) != null) { // 阻塞
    28             // 在通道里读数据,通道里可没有null!肿么办?
    29             // 判断自定义结束标志
    30             // if ("over".equals(line)) {
    31             //     break;
    32             // }
    33             bw.write(line);
    34             bw.newLine();
    35             bw.flush();
    36         }
    37 
    38         // 服务器给客户端反馈
    39         BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    40         bwServer.write("文件上传成功");
    41         bwServer.newLine();
    42         bwServer.flush();
    43 
    44         // 释放资源
    45         bw.close();
    46         s.close();
    47     }
    48 }
    UploadServer.java
                f:上传图片(字节流)
                    注意在通道字节流中要使用flush()刷新方法。否则数据会有丢失。
     1 package cn.itcast_13;
     2 
     3 import java.io.BufferedInputStream;
     4 import java.io.BufferedOutputStream;
     5 import java.io.FileInputStream;
     6 import java.io.IOException;
     7 import java.io.InputStream;
     8 import java.net.Socket;
     9 
    10 /*
    11  * 上传图片(字节流)
    12  * 
    13  * OutputStream抽象类的方法:
    14  *         public void flush() throws IOException
    15  *             刷新此输出流并强制写出所有缓冲的输出字节
    16  * 
    17  *             注意:在通道字节流中要使用flush()刷新方法。否则数据会有丢失。
    18  */
    19 public class UploadClient {
    20     public static void main(String[] args) throws IOException {
    21         // 创建客户端Socket对象
    22         Socket s = new Socket("192.168.40.9", 19191);
    23 
    24         // 封装图片文件对象(字节流)
    25         BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src//cn//itcast_13//林青霞.jpg"));
    26         
    27         // 封装通道内的流对象(字节流)
    28         BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
    29 
    30         byte[] bys = new byte[1024];
    31         int len = 0;
    32         while ((len = bis.read(bys)) != -1) {
    33             bos.write(bys, 0, len);
    34             bos.flush(); // 刷新此输出流并强制写出所有缓冲的输出字节
    35         }
    36         s.shutdownOutput();
    37 
    38         // 读取服务器的反馈
    39         InputStream is = s.getInputStream();
    40         byte[] bys2 = new byte[1024];
    41         int len2 = is.read(bys2);
    42         String client = new String(bys2, 0, len2);
    43         System.out.println(client);
    44 
    45         // 释放资源
    46         bis.close();
    47         s.close();
    48     }
    49 }
    UploadClient.java
     1 package cn.itcast_13;
     2 
     3 import java.io.BufferedInputStream;
     4 import java.io.BufferedOutputStream;
     5 import java.io.FileOutputStream;
     6 import java.io.IOException;
     7 import java.io.OutputStream;
     8 import java.net.ServerSocket;
     9 import java.net.Socket;
    10 
    11 /*
    12  * 上传图片(字节流)
    13  */
    14 public class UploadServer {
    15     public static void main(String[] args) throws IOException {
    16         // 创建服务器Socket对象
    17         ServerSocket ss = new ServerSocket(19191);
    18 
    19         // 监听客户端连接
    20         Socket s = ss.accept();
    21 
    22         // 封装通道内流对象(字节流)
    23         BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
    24         
    25         // 封装图片文件对象(字节流)
    26         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src//cn//itcast_13//mn.jpg"));
    27 
    28         byte[] bys = new byte[1024];
    29         int len = 0;
    30         while ((len = bis.read(bys)) != -1) {
    31             bos.write(bys, 0, len);
    32             bos.flush(); // 刷新此输出流并强制写出所有缓冲的输出字节
    33         }
    34 
    35         // 给客户端一个反馈
    36         OutputStream os = s.getOutputStream();
    37         os.write("图片上传成功".getBytes());
    38 
    39         bos.close();
    40         s.close();
    41     }
    42 }
    UploadServer.java
                g:多线程改进上传文件
                    服务器的代码用线程进行封装(多线程),这样可以模拟一个同时接收多人上传文件的服务器。
                    (用循环也可以但是效率低,是单线程的程序)
     1 package cn.itcast_15;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.BufferedWriter;
     5 import java.io.FileReader;
     6 import java.io.IOException;
     7 import java.io.InputStreamReader;
     8 import java.io.OutputStreamWriter;
     9 import java.net.Socket;
    10 
    11 public class UploadClient {
    12     public static void main(String[] args) throws IOException {
    13         // 创建客户端Socket对象
    14         Socket s = new Socket("192.168.40.9", 11111);
    15 
    16         // 封装文本文件
    17         BufferedReader br = new BufferedReader(new FileReader("src//cn//itcast_15//a.txt"));
    18         
    19         // 封装通道内的流对象
    20         BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    21 
    22         String line = null;
    23         while ((line = br.readLine()) != null) { // 阻塞
    24             bw.write(line);
    25             bw.newLine();
    26             bw.flush();
    27         }
    28 
    29         // Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了
    30         s.shutdownOutput();
    31 
    32         // 接收反馈
    33         BufferedReader brClient = new BufferedReader(new InputStreamReader(
    34                 s.getInputStream()));
    35         String client = brClient.readLine(); // 阻塞
    36         System.out.println(client);
    37 
    38         // 释放资源
    39         br.close();
    40         s.close();
    41     }
    42 }
    UploadClient.java
     1 package cn.itcast_15;
     2 
     3 import java.io.IOException;
     4 import java.net.ServerSocket;
     5 import java.net.Socket;
     6 
     7 public class UploadServer {
     8     public static void main(String[] args) throws IOException {
     9         // 创建服务器Socket对象
    10         ServerSocket ss = new ServerSocket(11111);
    11 
    12         while (true) {
    13             Socket s = ss.accept(); // 监听客户端连接
    14             new Thread(new UserThread(s)).start();
    15         }
    16     }
    17     
    18 }
    UploadServer.java
     1 package cn.itcast_15;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.BufferedWriter;
     5 import java.io.FileWriter;
     6 import java.io.IOException;
     7 import java.io.InputStreamReader;
     8 import java.io.OutputStreamWriter;
     9 import java.net.Socket;
    10 
    11 public class UserThread implements Runnable {
    12     
    13     private Socket s;
    14 
    15     public UserThread(Socket s) {
    16         this.s = s;
    17     }
    18 
    19     @Override
    20     public void run() {
    21         try {
    22             // 封装通道内的流对象
    23             BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    24             
    25             // 封装文本文件对象
    26             // BufferedWriter bw = new BufferedWriter(new FileWriter("src//cn//itcast_15//Copy.java"));
    27 
    28             // 为了防止名称冲突(即为了防止所有文件的名字都一样)
    29             String newName = System.currentTimeMillis() + ".txt";
    30             BufferedWriter bw = new BufferedWriter(new FileWriter("src//cn//itcast_15//" + newName));
    31             // 如果在某一时间点,同时有很多人访问服务器,相同名字的文件也会出现很多,肿么办? 答:再加循环判断,一旦某个名字存在,就重新赋值另一名字即可。
    32 
    33             String line = null;
    34             while ((line = br.readLine()) != null) { // 阻塞
    35                 bw.write(line);
    36                 bw.newLine();
    37                 bw.flush();
    38             }
    39 
    40             // 给出反馈
    41             BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    42             bwServer.write("文件上传成功");
    43             bwServer.newLine();
    44             bwServer.flush();
    45 
    46             // 释放资源
    47             bw.close();
    48             s.close();
    49         } catch (IOException e) {
    50             e.printStackTrace();
    51         }
    52     }
    53 
    54 }
    UserThread.java
                TCP传输容易出现的问题:    
                    客户端连接上服务端,两端都在等待,没有任何数据传输。
                通过例程分析:
                    因为read()方法或者readLine()方法是阻塞式 解决办法:
                    1.自定义结束标记。
                    2.使用shutdownInput()shutdownOutput()方法。
    =============================================================================
  • 相关阅读:
    一款前端文件上传工具
    聊一聊最近找工作的感受
    神秘的计算机网络----(1)
    月下无限连?拒绝无休止switch!
    计算机网络---序
    验证码识别
    两数之和
    Sanic框架基础之解决CORS跨域
    Sanic框架进阶之实现异步缓存组件
    asyncio异步模块的21个协程编写实例
  • 原文地址:https://www.cnblogs.com/chenmingjun/p/8799646.html
Copyright © 2011-2022 走看看