您现在的位置是:首页 > 文章详情

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

日期:2018-04-10点击:359

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 黑泽明军
【转载文章务必保留出处和署名,谢谢!】
原文链接:https://yq.aliyun.com/articles/607521
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章