网络编程进阶干货
案例一: 实现客户端与服务端的交互
频繁的客户端与服务端的通信
需求:
1. 客户端通过键盘录入发送数据到服务器端,
2. 服务器端将接收到的数据显示到屏幕上的同时, 将这些数据转成大写发回给客户端.
3. 当客户端录入的是 over 时, 该客户结束转换.
服务端
- package socket2.socketss;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import java.NET.ServerSocket;
- import java.NET.Socket;
- /**
- * 不管是服务端还是客户端都需要刷新.
- * readLine 方法是读取一行, 必须指定行终止符
- *
- * 1. 当没有使用 PrintWriter 构造方法中的, true 自动刷新时, 只能使用 flush
- * 2. 由于 readLine 方法必须要读到行终止符时才返回该数据,
- * 3. 因此需要用 +"/r/n" 或者属性集对象的换行常数的属性集
- * 4. 然而最高效的方法是使用 Println 方法打印一行.
- */
- public class Socket_Server {
- public static void main(String[] args) throws IOException {
- // 服务端:
- System.out.println("服务端运行......");
- // 思路:
- // 1. 创建服务端 SeverSocket 明确端口
- ServerSocket ss = new ServerSocket(10009);
- while (true) {
- // 服务端接收对象
- Socket s = ss.accept();
- // 2.socket 输入流, 读取客户端发过来的数据
- BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
- // 将转化成的大写字母数据返回给客户端 true 自动刷新
- // 3. 目的: socket 输出流, 将转成大写数据发给客户端
- PrintWriter pwOut = new PrintWriter(s.getOutputStream(), true);
- // 外加功能
- String IP = s.getInetAddress().getHostAddress();
- System.out.println(IP + "------connected");
- // 4. 频繁的读写操作
- // 5. 关闭该客户端
- // 创建 ServerSocket 对象, 并明确对象
- String line;
- while ((line = bufIn.readLine()) != null) {
- if (line.equals("over")) {
- break;
- }
- String LIN = line.toUpperCase();
- //println() 方法指定行终止符打印一行
- pwOut.println(LIN);
- System.out.println(LIN);
- }
- s.close();
- }
- }
- }
客户端
- package socket2.socketss;
- import java.io.*;
- import java.NET.Socket;
- /**
- * 客户端
- * 步骤:
- * 1. 创建 socket, 明确地址和端口
- * 2. 源: 键盘录入, 获取需要转换的数据
- * 3. 目的, 网络, socket 输出流, 将录入的数据发送到服务器
- * 4. 源 2:socket socket 读取流, 读取服务器发回来的大写数据
- * 5. 目的: 客户端显示, 将大写数据显示出来.
- * 6. 频繁读写操作
- * 7. 关闭资源
- */
- public class Socket_Client {
- public static void main(String[] args) throws IOException {
- // 客户端
- System.out.println("客户端运行......");
- // 步骤:
- // 1. 创建 socket, 明确地址和端口
- Socket s=new Socket("192.168.1.3",10009);
- // 2. 源: 键盘录入, 获取需要转换的数据
- BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
- // 3. 目的, 网络, socket 输出流, 将录入的数据发送到服务器
- /* OutputStream outSo=s.getOutputStream();
- // 由于都是字符数换流, 高效
- BufferedWriter buOut =new BufferedWriter(new OutputStreamWriter(outSo));*/
- // 为了更方便, 我们这使用打印流
- PrintWriter pwOut=new PrintWriter(s.getOutputStream(),true);
- // 4. 源 2:socket socket 读取流, 读取服务器发回来的大写数据
- BufferedReader buIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
- // 5. 目的: 客户端显示, 将大写数据显示出来.
- // 6. 频繁读写操作
- String line;
- while ((line=bf.readLine())!=null){
- // 将数据发送给服务端
- pwOut.println(line);
- if ("over".equals(line)) {
- break;
- }
- // 将服务端返回的数据读取出来, 并打印.
- String s1 = buIn.readLine();
- System.out.println(s1);
- }
- // 7. 关闭资源
- s.close();
- }
- }
案例三:
文件上传
服务端
- package socket;
- import java.io.*;
- import java.NET.ServerSocket;
- import java.NET.Socket;
- public class SeverSocket_File {
- public static void main(String[] args) throws IOException {
- // 服务端:
- System.out.println("服务端运行......");
- // 思路:
- // 1. 创建服务端 SeverSocket 明确端口
- ServerSocket ss = new ServerSocket(10010);
- System.out.println(ss.getInetAddress().getHostAddress() + "------------connected");
- // 服务端持续操作
- while (true) {
- // 服务端接收对象
- Socket s = ss.accept();
- // 2.socket 输入流, 读取客户端发过来的数据
- BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
- // 3. 目的: socket 输出流, 将上传成功的数据
- PrintWriter pw = new PrintWriter(new FileWriter("D:\\Java 代码 \\Java 基础加强 \\Day12_socket\\src\\s.txt"), true);
- // 4. 频繁的读写操作
- String line;
- while ((line = bufIn.readLine()) != null) {
- // if (line.equals("over")) {
- // break;
- // }
- pw.println(line);
- }
- // 服务端反馈数据给客户端
- PrintWriter out = new PrintWriter(s.getOutputStream(), true);
- out.println("文本上传成功");
- pw.close();
- s.close();
- }
- }
- }
客户端
- package socket;
- import java.io.*;
- import java.NET.Socket;
- /**
- * 文件上传
- * 原理:
- * 1. 客户端读取文件, 将数据发送给服务端 , 发送完毕标记
- * 2. 服务端接收并读取客户端发来的数据,
- * 3. 反馈 上传成功 的数据给客户端
- * 4. 客户端接收并读取服务端成功信息, 在这之前必须设定结束标记
- */
- public class Client_file {
- public static void main(String[] args) throws IOException {
- // 客户端
- System.out.println("客户端运行......");
- // 步骤:
- // 1. 创建 socket, 明确地址和端口
- Socket s = new Socket("192.168.1.3", 10010);
- // 2. 源: 键盘录入, 获取需要转换的数据
- BufferedReader bf = new BufferedReader(new FileReader("D:\\Java 代码 \\Java 基础加强 \\ 笔记. txt"));
- // 3. 目的, 网络, socket 输出流, 将文本中的数据发送到服务器
- PrintWriter pwOut = new PrintWriter(s.getOutputStream(), true);
- // 4. 频繁读写操作
- String line;
- while ((line = bf.readLine()) != null) {
- // 将数据发送给服务端
- pwOut.println(line);
- }
- // 为了上传成功后, 客户端能正常关闭, 我们需要定义一个结束标记
- // pwOut.println("over");
- // 为了使得程序更吊一点, 我们使用 socket 中的 shutdownOutput().
- s.shutdownOutput();
- // 5. 源 2:socket socket 读取流. 读取服务端发回来的上传成功信息
- BufferedReader buIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
- String info = buIn.readLine();
- System.out.println(info);
- // 7. 关闭资源
- s.close();
- bf.close();
- }
- }
媒体文件的上传:
为什么不能使用字符流来上传或者复制媒体文件
原因:
编码表中的数据不能完全包含字节二进制数据
导致一种情况就是: 无法解析某些字而出现乱码.
图片上传服务端
- package socket3_pic;
- import java.io.*;
- import java.NET.ServerSocket;
- import java.NET.Socket;
- public class SeverSocketDemo {
- public static void main(String[] args) throws IOException {
- System.out.println("服务端运行......");
- // 创建 ServerSocket 对象
- ServerSocket ss = new ServerSocket(10011);
- // 创建 socket 对象
- while (true) {
- Socket s = ss.accept();
- String ip = s.getInetAddress().getHostAddress();
- System.out.println(ip+"--------connected");
- // 源: 客户端获取的流
- InputStream sin = s.getInputStream();
- // 目的: 写入文件当中, 需要使用文件 File(非流类) 类
- File f=new File("D:\\Java 代码 \\Java 基础加强 \\Day12_socket\\src\\socket");
- if (!f.exists()) {
- f.mkdir();
- }
- int conut=1;
- // 为了使得上传的文件不冲突, 使用 ip 和遍历文件夹是否存在, 计数器来限制文件名
- File file=new File(f,ip+"("+conut+")"+".jpg");
- while (file.exists()){
- conut++;
- file=new File(f,ip+"("+conut+")"+".jpg");
- }
- FileOutputStream out = new FileOutputStream(file);
- // 频繁读写操作
- int len;
- byte[] bytes = new byte[1024 * 1024];
- while ((len = sin.read(bytes)) != -1) {
- // 将缓冲区中的数据全部写入到文件当中
- out.write(bytes, 0, len);
- }
- // 如果图片上传成功后, 发送提示给客户端
- OutputStream sOut = s.getOutputStream();
- sOut.write("图片上传完毕".getBytes());
- s.close();
- out.close();
- }
- }
- }
客户端
- package socket3_pic;
- import java.io.*;
- import java.NET.Socket;
- public class UploadPicClient {
- public static void main(String[] args) throws IOException {
- System.out.println("客户端运行.......");
- // 创建 socket
- Socket s = new Socket("192.168.1.3", 10011);
- // 获取字节数据源
- FileInputStream fin = new FileInputStream(new File("D:\\Java 代码 \\Java 基础加强 \\Day12_socket\\1.jpg"));
- // 目的源: socket
- OutputStream out = s.getOutputStream();
- // 频繁读写
- int len = 0;
- byte[] bytes = new byte[1024 * 1024];
- while ((len = fin.read(bytes)) != -1) {
- out.write(bytes, 0, len);
- }
- // 结束标记, 告诉服务端图片数据发送完毕, 不要再继续读取了
- s.shutdownOutput();
- // 读取服务端返回的图片上传状态
- InputStream sin = s.getInputStream();
- byte[] bytes1 = new byte[1024];
- int read = sin.read(bytes1);
- System.out.println(new String(bytes1, 0, read));
- // 关闭资源
- fin.close();
- s.close();
- }
- }
来源: http://www.jianshu.com/p/b74d609ef3eb