1.首先放上我项目目录(java原生 不需要第三方依赖)
1.首先代码我一一附上
(1)StartServer.java
import java.net.ServerSocket;
import java.net.Socket;
public class StartServer {
// 服务端的启动类
public static void main(String[] args) {
// 服务端
try{
//创建服务器socket连接
ServerSocket serverSocket=new ServerSocket(18889);
//这里写成while循环 是为了 让一个客户端连接后 另一个客户端还可以连接
int i=0;
while(true){
Socket socket=serverSocket.accept();
new SocketServerThread(socket).start();
i++;
System.out.println("当前有"+i+"个客户端,与服务器建立了连接。");
}
}catch(Exception e){
e.printStackTrace();
}
}
}
(2)StartClient.java
import java.net.Socket;
public class StartClient {
// 客户端的启动类
public static void main(String[] args) {
// 这里 我启动了两个客户端 便于测试 一般写一个就可以了
//客户端1
try{
//创建socket连接 服务器的地址是127.0.0.1:18889
Socket socket=new Socket("127.0.0.1",18889);
//启动客户端
new SocketClient(socket).startSocketClient();
}catch(Exception e){
e.printStackTrace();
}
//客户端2
try{
//创建socket连接 服务器的地址是127.0.0.1:18889
Socket socket=new Socket("127.0.0.1",18889);
//启动客户端
new SocketClient(socket).startSocketClient();
}catch(Exception e){
e.printStackTrace();
}
}
}
(3)SocketUtils.java
public class SocketUtils {
// cs架构的 工具类 后续可以根据自己的需求 写工具方法
public static final String streamEncoding = "utf-8";
}
(4)SocketServerThread.java
import java.io.*;
import java.net.Socket;
//服务器线程类
public class SocketServerThread extends Thread{
private Socket socket;
public SocketServerThread(Socket socket){
this.socket=socket;
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
@Override
public void run(){
// 这里写成循环 是因为 如果不写循环 处理发生错误 本条线程就结束 也就和客户端失去了联系
// 写成循环 只要socket对象存在 InputStreamReader OutputStreamWriter 就可以重新建立 继续发送接受消息
while (true){
try{
//从socket获取 接收 和发送消息的流
BufferedReader bfr = new BufferedReader(new InputStreamReader(socket.getInputStream(), SocketUtils.streamEncoding));
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), SocketUtils.streamEncoding));
//从客户端接收消息 这里需要注意
// 这里的循环 只要没有出现Exception 用户和客户端的连接没有断开 下面这个循环 就不会终止
// 以前 我以为 服务端每接收一条消息然后回复出去 这个while就会终止 但实际不是这样的 这个InputStream 和 OutputStream 是一直保持连接的
// 是需要一直循环 从里面获取消息和发送消息的
String line = "";
while((line = bfr.readLine())!=null){
bfw.write("我已收到你的消息【"+line+"】");
bfw.newLine();
bfw.flush();
System.out.println("接收到了客户发来的消息:"+line);
System.out.println("同时向客户端回复了:我已收到你的消息【"+line+"】");
}
}catch(Exception e){
System.out.println("连接断开!");
if(socket!=null){
try{
if(!socket.isClosed()){
socket.close();
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
break;
}
}
}
}
(5)SocketClient.java
import java.net.Socket;
public class SocketClient {
private Socket socket;
public SocketClient(Socket socket) {
this.socket = socket;
}
// 对于客户端来说 启动客户端 就需要启动两个线程 一个是发送线程 一个是接收线程 因为
// 发送消息后 需要等待 服务端回消息 在等待过程中 就需要接收线程监听 与此同时 发送线程还可以继续发送消息
// 对于服务端而言 就只需要一条线程 即 接受到客户端消息-》处理-》回复
public void startSocketClient(){
try{
new SocketClientSendThread(socket).start();
new SocketClientReceiveThread(socket).start();
}catch(Exception e){
e.printStackTrace();
}
}
}
(6)SocketClientSendThread.java
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
//向服务端发送消息线程
public class SocketClientSendThread extends Thread{
private Socket socket;
public SocketClientSendThread(Socket socket){
this.socket=socket;
}
@Override
public void run(){
while (true){
try{
// 等待3秒
Thread.sleep(3000);
// 然后把信息写到 OutputStream 流里面 然后服务器就能从这个流里读取数据
String send = "客户(线程)"+Thread.currentThread().getName()+"向 \n 服务器发送消息。";
BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bfw.write(send);
bfw.newLine();
bfw.flush();
System.out.println("给服务端发送的信息:"+send);
}catch(Exception e){
System.out.println("链接断开");
if(socket!=null){
try{
if(!socket.isClosed()){
socket.close();
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
break;
}
}
}
}
(7)SocketClientReceiveThread.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
// 客户端接收线程
public class SocketClientReceiveThread extends Thread{
private Socket socket;
public SocketClientReceiveThread(Socket socket){
this.socket=socket;
}
@Override
public void run(){
// 这个循环也是 只要socket存在 出现异常 也会立即新建 InputStream接收流 及时获取服务器的信息
while(true){
try{
// 服务端会把回复消息写到 这个InputStream 流里面
// 这里客户端从这里就能获取服务端回复的消息
BufferedReader bfr = new BufferedReader(new InputStreamReader(socket.getInputStream(), SocketUtils.streamEncoding));
String line = "";
// 同服务端一样 这里的循环只要连接保持 这个循环就不会终止 需要一直遍历 从里面 读取服务端消息
while((line = bfr.readLine())!=null){
System.out.println("接收到服务器回复过来的消息:"+line);
}
}catch(Exception e){
System.out.println("链接断开");
if(socket!=null){
try{
if(!socket.isClosed()){
socket.close();
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
break;
}
}
}
}
2.系统的各种解释 我已经在代码的注释里写清楚了 但是这里有一点需要注意
我从流里读取消息使用的是 .readLine() 也就是一行读取一次,默认 一行就是一个消息,如果你一个消息里有个 \n 回车 他就会当作两个消息处理 所以使用的时候要注意,
这里我提供两个建议 1.客户端和服务端发送消息时候 替换 \n 为其他字符 输出时候再替换回来
2.将 BufferedReader 替换为其他输入流 一次性读取所有的消息 例如.read(new byte[2048])
如果代码里有不懂的地方 欢迎评论区留言。