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

  1. 云栖社区>
  2. 博客>
  3. 正文

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

黑泽明军 2018-04-11 23:51:00 浏览561
展开阅读全文

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()方法。
=============================================================================

 

我的GitHub地址:https://github.com/heizemingjun
我的博客园地址:http://www.cnblogs.com/chenmingjun
我的蚂蚁笔记博客地址:http://blog.leanote.com/chenmingjun
Copyright ©2018 黑泽明军
【转载文章务必保留出处和署名,谢谢!】

网友评论

登录后评论
0/500
评论
黑泽明军
+ 关注