前言:虽然Nginx帮我们做好了负载均衡,Tomcat则帮我们完成TCP连接的建立,HTTP请求的处理,但了解其底层传输的网络编程也是十分重要的。
我们以TCP传输为例,来具体实现两个需求。
一.传输字
二.传输一张图片
(我们先从简单的传输字符开始 图片与之同理)
需求一: 在自己主机上设置端口号为9998为服务端,要求服务端在接受到客户端发来的消息之后,能够回复消息。
服务端
package com.net_test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* written by 刘瑞臻
* time:2022/12/13 19:44
*/
public class socket_server02 {
public static void main(String[] args) throws IOException {
//收客户端消息
ServerSocket serverSocket = new ServerSocket(9998);//设置端口号
Socket accept = serverSocket.accept();//建立连接通道socket
InputStream inputStream = accept.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));//将字节流转换成字符流 效率比较高
String s = bufferedReader.readLine();
System.out.println(s);
// bufferedReader.close();
//向客户端发消息
OutputStream outputStream = accept.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello客户端 这里是服务端");
bufferedWriter.newLine();
bufferedWriter.flush();//刷新通道 才能二次传输
bufferedWriter.close();
bufferedReader.close();
serverSocket.close();
}
}
客户端
package com.net_test;
import com.sun.jmx.snmp.InetAddressAcl;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
* written by 刘瑞臻
* time:2022/12/13 19:44
*/
public class socket_client02 {
public static void main(String[] args) throws IOException {
//给服务端发消息
Socket socket = new Socket(InetAddress.getLocalHost(),9998);//通过本地地址与端口号连接上服务端
OutputStream outputStream = socket.getOutputStream();//创建一个输出流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello,server这里是client 字符流");
bufferedWriter.newLine();
bufferedWriter.flush();//清除一下网络缓存
//收服务端的消息
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
bufferedReader.close();
bufferedWriter.close();
socket.close();
}
}
需求二: 要求客户端向服务端传输一张图片,服务端收到图片后向客户端回应。
服务端
package com.net_test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* written by 刘瑞臻
* time:2022/12/15 11:31
*/
@SuppressWarnings({"all"})
public class socket_server_acpic {
public static void main(String[] args) throws Exception {
//收客户端消息
ServerSocket serverSocket = new ServerSocket(8889);
System.out.println("服务端正在8889端口监听...");
Socket accept = serverSocket.accept();
//搭建好接受的通道 socket.accept
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
//接收文件流 并将其保存在byte数组
byte[] bytes = StreamUtils.streamToByteArray(bis);
//将字节写到指定路径
String descPath = "D:\\IO_test\\csdn.jpg" ;
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(descPath));
//将图片的二进制文件写入到目标地址
bufferedOutputStream.write(bytes);
bufferedOutputStream.close();
//向客户端发送消息 表示服务端已经接受到了图片
OutputStream outputStream = accept.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("服务端已经收到图片");
bufferedWriter.flush();//清除原来图片传输时占用的通道 重新刷新
accept.shutdownOutput();
bis.close();
accept.close();
serverSocket.close();
}
}
客户端
package com.net_test;
import java.awt.*;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
* written by 刘瑞臻
* time:2022/12/15 11:33
*/
@SuppressWarnings({"all"})
public class socket_client_senpic {
public static void main(String[] args) throws Exception {
//给服务端发照片
Socket socket = new Socket(InetAddress.getLocalHost(),8889);
String filepath = "C:\\Users\\lrzlx\\Desktop\\work\\net_test\\src\\Screenshot_20221209_214700.jpg";
//读取文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filepath));
//将图片转换成字节 bytes此时便是图片的另一种形式
byte[] bytes = StreamUtils.streamToByteArray(bis);
//用socket通道 将图片的文件流传输
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
bis.close();
// bis.close();
socket.shutdownOutput();//传输结束
//接受服务端消息
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
// bufferedReader.close();
// socket.shutdownOutput();//传输结束
bos.close();
bufferedReader.close();
socket.close();
}
}
总结:无论怎样传,或者传什么,客户端与服务端之间都必须建立一个"通道',socket便是这个通道,在服务端是socket.accept,在客户端是socke,字符流也好字节流也好,都必须将流通过这个通道传输。
另外,在启动过程中也要注意,服务端一定要先启动 。