Java socket编程学习笔记
2024-01-07 17:29:18
一、初步了解
1、简易代码(存在socket提前关闭问题)
服务端代码:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class MySocketServer {
public static void main(String[] args) throws IOException {
// 创建一个serverSocket,监听一个端口号并创建通信socket
ServerSocket serverSocket = new ServerSocket(8888);
// 当有客户端连接时创建一个通信socket,没有连接时会阻塞
Socket socket = serverSocket.accept();
// 打印客户端信息
System.out.println("客户端" + socket.getInetAddress().getLocalHost() + "连接到服务器");
// 输入流,用于读取客户端信息
InputStream in = socket.getInputStream();
// 良好习惯,关闭输出流
in.close();
// 输出流,用于给客户端返回信息
OutputStream out = socket.getOutputStream();
/* 读取客户端信息 */
byte[] buffer = new byte[1024];
int len;
StringBuilder msgBuilder = new StringBuilder();
while ((len = in.read(buffer)) != -1) {
msgBuilder.append(new String(buffer, 0, len));
}
// 打印从客户端收到的信息
System.out.println("服务端接收到消息:" + msgBuilder.toString());
// 给客户端返回信息
out.write(("服务端收到消息:" + msgBuilder.toString()).getBytes(StandardCharsets.UTF_8) );
// 输出缓冲数据
out.flush();
// 关闭输出流
out.close();
}
}
客户端代码
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
public class MySocketClient {
public static void main(String[] args) throws IOException {
// 指定ip和端口号,创建socket连接
Socket socket = new Socket("127.0.0.1", 8888);
/* 发送消息 */
String msg = "客户端发送了一条消息,现在是北京时间" + new Date();
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
out.write(msg.getBytes(StandardCharsets.UTF_8));
out.flush();
// 关闭输出流
out.close();
/* 读取信息 */
byte[] buffer = new byte[1024];
int len;
StringBuilder msgBuilder = new StringBuilder();
while ((len = in.read(buffer)) != -1) {
msgBuilder.append(new String(buffer, 0, len));
}
// 打印收到信息
System.out.println("客户端收到服务端回信:" + msgBuilder);
// 关闭输入流
in.close();
}
}
运行结果
? 1、步骤:先启动服务端,再启动客户端
? 2、服务端打印:
客户端LAPTOP-EECN3AOI/192.168.31.39连接到服务器
Exception in thread "main" java.net.SocketException: Socket is closed
at java.net.Socket.getOutputStream(Socket.java:943)
at MySocketServer.main(MySocketServer.java:19)
?3、客户端打印:
Exception in thread "main" java.net.SocketException: socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.net.SocketInputStream.read(SocketInputStream.java:127)
at MySocketClient.main(MySocketClient.java:24)
? 4、错误分析:socket被关闭
? 5、原因:分析代码,未对socket进行关闭,但是客户端在通信完成前提前关闭了out流,服务端提前关闭了in流,查询资料得知关闭流会导致socket关闭
2、将所有关闭流操作去掉,存在死锁问题
服务端
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class MySocketServer {
public static void main(String[] args) throws IOException {
// 创建一个serverSocket,监听一个端口号并创建通信socket
ServerSocket serverSocket = new ServerSocket(8888);
// 当有客户端连接时创建一个通信socket,没有连接时会阻塞
Socket socket = serverSocket.accept();
// 打印客户端信息
System.out.println("客户端" + socket.getInetAddress().getLocalHost() + "连接到服务器");
// 输入流,用于读取客户端信息
InputStream in = socket.getInputStream();
// 输出流,用于给客户端返回信息
OutputStream out = socket.getOutputStream();
/* 读取客户端信息 */
byte[] buffer = new byte[1024];
int len;
StringBuilder msgBuilder = new StringBuilder();
while ((len = in.read(buffer)) != -1) {
msgBuilder.append(new String(buffer, 0, len));
}
// 打印从客户端收到的信息
System.out.println("服务端接收到消息:" + msgBuilder.toString());
// 给客户端返回信息
out.write(("服务端收到消息:" + msgBuilder.toString()).getBytes(StandardCharsets.UTF_8) );
}
}
客户端
public class MySocketClient {
public static void main(String[] args) throws IOException {
// 指定ip和端口号,创建socket连接
Socket socket = new Socket("127.0.0.1", 8888);
/* 发送消息 */
String msg = "客户端发送了一条消息,现在是北京时间" + new Date();
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
out.write(msg.getBytes(StandardCharsets.UTF_8));
out.flush();
/* 读取信息 */
byte[] buffer = new byte[1024];
int len;
StringBuilder msgBuilder = new StringBuilder();
while ((len = in.read(buffer)) != -1) {
msgBuilder.append(new String(buffer, 0, len));
}
// 打印收到信息
System.out.println("客户端收到服务端回信:" + msgBuilder);
}
}
运行结果
?1、服务端:打印连接信息后无响应
客户端LAPTOP-EECN3AOI/192.168.31.39连接到服务器
? 2、客户端:无响应
? 3、原因:分析代码,服务端没有打印出客户端发送消息,猜测是以下代码陷入死循环。
byte[] buffer = new byte[1024];
int len;
StringBuilder msgBuilder = new StringBuilder();
while ((len = in.read(buffer)) != -1) {
msgBuilder.append(new String(buffer, 0, len));
}
? 查资料得知,在普通流当中,这个方法可行。但是在socket中,只有当对方将输出流关闭后才会以-1作为结束标志,故而陷入死循环,推断正确。
? 4、解决方法:需要关闭流的同时,不关闭socket,可使用Socket::shutdownOutput()方法和Socket::shutdownInput()方法实现
3、使用正确方法关闭流,通信成功
服务端
public class MySocketServer {
public static void main(String[] args) throws IOException {
// 创建一个serverSocket,监听一个端口号并创建通信socket
ServerSocket serverSocket = new ServerSocket(8888);
// 当有客户端连接时创建一个通信socket,没有连接时会阻塞
Socket socket = serverSocket.accept();
// 打印客户端信息
System.out.println("客户端" + socket.getInetAddress().getLocalHost() + "连接到服务器");
// 输入流,用于读取客户端信息
InputStream in = socket.getInputStream();
// 输出流,用于给客户端返回信息
OutputStream out = socket.getOutputStream();
/* 读取客户端信息 */
byte[] buffer = new byte[1024];
int len;
StringBuilder msgBuilder = new StringBuilder();
while ((len = in.read(buffer)) != -1) {
msgBuilder.append(new String(buffer, 0, len));
}
// 关闭输入流
socket.shutdownInput();
// 打印从客户端收到的信息
System.out.println("服务端接收到消息:" + msgBuilder.toString());
// 给客户端返回信息
out.write(("服务端收到消息:" + msgBuilder.toString()).getBytes(StandardCharsets.UTF_8) );
// 关闭输出流同时关闭socket
out.close();
}
}
客户端
public class MySocketClient {
public static void main(String[] args) throws IOException {
// 指定ip和端口号,创建socket连接
Socket socket = new Socket("127.0.0.1", 8888);
/* 发送消息 */
String msg = "客户端发送了一条消息,现在是北京时间" + new Date();
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
out.write(msg.getBytes(StandardCharsets.UTF_8));
out.flush();
// 关闭输出流
socket.shutdownOutput();
/* 读取信息 */
byte[] buffer = new byte[1024];
int len;
StringBuilder msgBuilder = new StringBuilder();
while ((len = in.read(buffer)) != -1) {
msgBuilder.append(new String(buffer, 0, len));
}
// 打印收到信息
System.out.println("客户端收到服务端回信:" + msgBuilder);
// 关闭输入流同时关闭socket
in.close();
}
}
输出结果
? 1、服务端
客户端LAPTOP-EECN3AOI/192.168.31.39连接到服务器
服务端接收到消息:客户端发送了一条消息,现在是北京时间Sun Jan 07 16:46:26 GMT+08:00 2024
? 2、客户端
客户端收到服务端回信:服务端收到消息:客户端发送了一条消息,现在是北京时间Sun Jan 07 16:46:26 GMT+08:00 2024
4、心得
(1)关闭socket的 输入/输出流 时,会将socket连接一起关闭,当socket还需要继续工作时,需要使用内置方法shutdownOutput和shutdownInput关闭流
(2)输入流只有当对方输出流关闭时,才会以-1作为标志
文章来源:https://blog.csdn.net/weixin_48460141/article/details/135441201
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!