简介:
初步实现Java不同项目间的数据传输,后续会尝试对文本图片传输。
效果展示:
客户端输入:
服务端接收:
知识:
服务端解析:
port
是 服务器监听的端口号(范围0 - 65535
,推荐使用1024 以上
的端口)- 但是注意不要设到已被占用的端口号了
- Address already in use(设置到已经被占用的端口号报错)
int port = 8888;
- 补充:查询端口号是否被占用:
- 在 PowerShell(
Win + X
→ 选择 Windows 终端(管理员))中输入:(把8080替换成想要查询的端口)
Get-NetTCPConnection -LocalPort 8080
端口被占用:
端口没有被占用:
- 创建一个 TCP 服务器套接字,并在指定的
port
端口上 监听客户端连接- 这个
serverSocket
会一直等待客户端的连接,直到调用serverSocket.close();
关闭它
- 这个
ServerSocket serverSocket = new ServerSocket(port);
- 等待客户端连接,当有客户端连接时,返回
Socket
对象。- 代码会阻塞(停在这里),直到有客户端连接
Socket socket = serverSocket.accept();
- 获取客户端发送的输入流
InputStream inputStream = socket.getInputStream();
- 使用 缓冲读取,按行读取客户端数据,提高效率
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
客户端解析:
- 必须与服务器端口一致,否则无法连接
int port = 8888;
- 创建 Socket 客户端,连接到本机服务器(
InetAddress.getLocalHost()
)
Socket socket = new Socket(InetAddress.getLocalHost(), port);
- 获取输出流,用于向服务器发送数据
OutputStream outputStream = socket.getOutputStream();
- 添加
\n
:确保服务器的readLine()
可以正确读取。 - 使用 UTF-8 编码,保证字符兼容性
socket.getOutputStream().write((message+"\n").getBytes(StandardCharsets.UTF_8));
- 强制发送数据,避免缓冲区未满时服务器接收不到数据
outputStream.flush();
代码:
客户端:
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
int port = 8888;
try (Socket socket = new Socket(InetAddress.getLocalHost(), port);
OutputStream outputStream = socket.getOutputStream();
Scanner scanner = new Scanner(System.in);
) {
System.out.println("链接到服务器,输入消息发送,输入“exit”退出");
while (true) {
String message = scanner.nextLine();
if (message.equals("exit")) {
System.out.println("已断开连接");
break;
}
socket.getOutputStream().write((message+"\n").getBytes(StandardCharsets.UTF_8));
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Main {
public static void main(String[] args) {
int port = 8888;
System.out.println("等待客户端连接………………");
try (ServerSocket serverSocket = new ServerSocket(port);) {
Socket socket = serverSocket.accept();
System.out.println("客户端连接: " + socket.getInetAddress());
InputStream inputStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String message;
while ((message = reader.readLine()) != null) { // 按行读取
System.out.println("收到消息: " + message);
}
} catch (IOException e) {
System.out.println("客户端断开连接");
e.printStackTrace();
}
System.out.println("客户端主动断开");
}
}
问题注意:
无消息显示
服务端和客户端连接上了,但是在客户端输入信息,服务端接收不到,可以检查下面的两个代码:
socket.getOutputStream().write((message+"\n").getBytes(StandardCharsets.UTF_8));
- 这个message后面的“\n”一定要有,没有换行符
\n
,会导致服务器readLine()
无法读取完整消息,始终在等待,从而显示出没有消息接收到
outputStream.flush();
-
write()
只是写入缓冲区,没有flush()
,数据不会立即发送,可能导致服务器一直等不到数据。
补充多线程:
效果展示:
代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
public class send implements Runnable{
DatagramSocket datagramSocket=null;
BufferedReader bufferedReader=null;
private int portFrom;
private int portTo;
private String ip;
public send(String ip,int portFrom,int portTo){
this.portFrom=portFrom;
this.portTo=portTo;
this.ip = ip;
try {
this.datagramSocket = new DatagramSocket(portFrom);
this.bufferedReader = new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try {
String string = bufferedReader.readLine();
DatagramPacket datagramPacket = new DatagramPacket(string.getBytes(StandardCharsets.UTF_8), string.length(), new InetSocketAddress(this.ip, this.portTo));
datagramPacket.getData();
datagramSocket.send(datagramPacket);
if( string.equals("bye")){
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class receive implements Runnable {
DatagramSocket datagramSocket=null;
private int port;
public receive(int port){
this.port=port;
try {
this.datagramSocket = new DatagramSocket(this.port);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while(true){
try {
byte[] by=new byte[1024];
DatagramPacket data = new DatagramPacket(by,0,by.length);
this.datagramSocket.receive(data);
int length = data.getLength(); // 获取实际接收到的字节数
String string = new String(by, 0, length); // 正确的字符串转换
/*String string = new String(by, 0, length, StandardCharsets.UTF_8);
别这么写,这么写会导致,打印前面的字符串打印不出来!!!
*/
System.out.println("receive: " + string);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public class peopleA {
public static void main(String[] args) {
new Thread(new send("localhost",8887,9999)).start();
new Thread(new receive(7777)).start();
}
}
public class peopleB {
public static void main(String[] args) {
new Thread(new send("localhost",8889,7777)).start();
new Thread(new receive(9999)).start();
}
}
注意点:
String string = new String(by, 0, length, StandardCharsets.UTF_8);别这么写,这么写会导致,打印前面的字符串打印不出来!!!回头再探究.