Java 网络编程详解系列文章目录:
在上一篇关于 Java 网络编程的文章中【Java网络编程详解(一)】,我们介绍网络通信的一些基础概念,如:OSI网络模型、TCP/IP 网络模型、UDP 协议、TCP 协议以及 Java 中如何实现网络编程。
Java 网络编程实现图片上传
这一次我们来学习下,如何通过 Java 网络编程实现图片上传功能。
下面来完成一个上传图片的功能,这和前面的上传文件没有什么区别。只不过操作文件的时候使用的流对象是字节流而已!
//服务器端
public class TcpImage {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(10909);
Socket client = server.accept();
// 获取客户端的输入流
InputStream is = client.getInputStream();
// 获取客户端的输出流
OutputStream out = client.getOutputStream();
// 文件存放的位置
OutputStream os = new FileOutputStream("server.jpg");
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
// 反馈信息给客户端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("图片上传完成");
bw.flush();
os.close();
client.close();
server.close();
}
}
// 客户端
class Client {
public static void main(String[] args) throws Exception {
// 创建客户端服务对象
Socket socket = new Socket("192.168.1.102", 10909);
InputStream in = new FileInputStream("D:\\imagetest\\desk.jpg");
// 获取客户端的输出流对象
OutputStream os = socket.getOutputStream();
// 获取客户端的输入流对象
InputStream is = socket.getInputStream();
byte[] buffIn = new byte[1024];
int len = 0;
while ((len = in.read(buffIn)) != -1) {
os.write(buffIn, 0, len);
}
// 告诉服务器我已经发送完毕
socket.shutdownOutput();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String message = br.readLine();
System.out.println(message);
in.close();
socket.close();
}
}
程序运行结果如下图所示:
我们知道这是单线程,一次只能服务一个客户端。当客户端 A 连接后,被服务器端获取到,服务器执行具体流程,这时B客户端连接,只能等待,因为服务器的端还没有处理完客户端 A 的请求,如果很多客户端都要和我这个服务器通讯的话,这个时候怎么办呢?最好服务器端将每个客户端封装到不同的线程里,这样就可以处理多个客户端请求了。
那么现在我们来实现一下,多个客户端实现文件上传:
public class TcpThreads implements Runnable {
private Socket socket;
public TcpThreads(Socket socket) {
this.socket = socket;
}
public void run() {
int count = 1;
String ip = socket.getInetAddress().getHostAddress();
try {
System.out.println(ip + "............connected");
// 获取客户端的输入流
File file = new File(ip + ".jpg");
// 如果文件已经存在,则修改名称使之加一,直到名称不等
while (file.exists())
file = new File(ip + "(" + (count++) + ")" + ".jpg");
InputStream is = socket.getInputStream();
// 获取客户端的输出流
OutputStream out = socket.getOutputStream();
// 文件存放的位置
OutputStream os = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
// 反馈信息给客户端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("图片上传完成");
bw.flush();
os.close();
socket.close();
} catch (Exception e) {
throw new RuntimeException(ip + "上传失败");
}
}
}
class ClientImage {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.out.println("请输入一个文件有效路径");
return;
}
File file = new File(args[0]);
if (!(file.exists() && file.isFile())) {
System.out.println("该文件已经存在,或者不是一个文件");
return;
}
long maxSize = 1024 * 1024 * 5;
if (file.length() > maxSize) {
System.out.println("文件不能大于5M");
return;
}
if(!file.getName().endsWith(".jpg")){
System.out.println("文件只能是JPG");
return;
}
// 创建客户端服务对象
Socket socket = new Socket("192.168.1.102", 12345);
InputStream in = new FileInputStream(file);
// 获取客户端的输出流对象
OutputStream os = socket.getOutputStream();
// 获取客户端的输入流对象
InputStream is = socket.getInputStream();
byte[] buffIn = new byte[1024];
int len = 0;
while ((len = in.read(buffIn)) != -1) {
os.write(buffIn, 0, len);
}
// 告诉服务器我已经发送完毕
socket.shutdownOutput();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String message = br.readLine();
System.out.println(message);
in.close();
socket.close();
}
}
// 对上面的客户端、服务端程序进行测试
class ServerImage {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(12345);
while (true) {
Socket socket = server.accept();// 阻塞式方法,当获取到客户端对象,就创建线程
new Thread(new TcpThreads(socket)).start();
}
}
}
现在就可以对多个客户端服务了,从上面的服务端的代码可以发现:while(true) 说明服务器是一直开着的,可以不断的接收客户端的请求。
程序运行结果,如下图所示:
又因为 accept() 是阻塞式方法,当没有客户端请求服务器时,服务器一直处于阻塞状态,直到有客户端请求。如果有多个客户端访问,也会创建一个新线程为该客户端服务,因为服务器处理代码已经封装到了 run() 方法里面去了!
Java 网络编程实现并发登陆
接下来我们实现一个与上面程序类似的小程序:TCP 客户端并发登录。
// 服务器端程序
class ServerLogon implements Runnable {
private Socket socket;
public ServerLogon(Socket socket) {
this.socket = socket;
}
public void run() {
String ip = socket.getInetAddress().getHostAddress();
try {
//打印客户端的ip
System.out.println(ip + "............. connected!");
BufferedReader br = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
// 只有三次尝试的机会
for (int i = 0; i < 3; i++) {
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream("user.txt")));
String username = br.readLine();
//如果用户直接退出
if (username == null) {
break;
}
String line = null;
boolean flag = false;
while ((line = reader.readLine()) != null) {
if (line.equals(username)) {
flag = true;
break;
}
}
//如果用户名相同
if (flag) {
System.out.println(username + "登录成功");
pw.println("欢迎登录");
}else {
System.out.println(username + "尝试登录");
pw.println("无效的用户名");
}
reader.close();
}
socket.close();
} catch (IOException e) {
throw new RuntimeException(ip + "连接失败");
}
}
}
// 客户端程序
class UserClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("192.168.1.102", 11111);
PrintWriter bw = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
for (int i = 0; i < 3; i++) {
String name = br.readLine();
System.out.println(name);
//如果客户端按Ctrl+c
if (name == null)
break;
bw.println(name);
String message = in.readLine();
System.out.println(message);
if (message.contains("欢迎")) {
break;
}
}
br.close();
socket.close();
}
}
// 测试程序
public class TcpLogon {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(11111);
while (true) {
Socket socket = server.accept();
new Thread(new ServerLogon(socket)).start();
}
}
}
用户信息如下所示:
其实,我们写的客户端与服务端,程序不管是多线程还是单线程,它的总体思想是不变的,它们都是和 I/O 流一起使用的,管服务器多么复杂,基本的原理还是这样的。学好这些,有助于我们以后理解学习和使用服务器 如 Tomcat 等 Web 服务器。