软件编程
位置:首页>> 软件编程>> java编程>> JAVA实现SOCKET多客户端通信的案例

JAVA实现SOCKET多客户端通信的案例

作者:黎明的影  发布时间:2023-08-26 19:10:35 

标签:JAVA,SOCKET,客户端,通信

一、ServerSocket

1.为了方便调试,先创建一个界面用于显示客户端连接信息

JAVA实现SOCKET多客户端通信的案例

基于javafx包写的一个简单界面!


javafx.scene.control.TextArea ta = new javafx.scene.control.TextArea();
@Override
public void start(Stage primaryStage) throws Exception {
 scene = new Scene(ta,450,200);
 primaryStage.setTitle("SocketServer");
 primaryStage.setScene(scene);
 primaryStage.show();
 pStage = primaryStage;
 new Thread(new MyServer()).start(); //创建线程启动Socket服务
 }

2.启动Socket服务


public class MyServer implements Runnable{
 @Override
 public void run() {
  try{
   java.net.ServerSocket serverSocket = new java.net.ServerSocket(8000);
   ta.appendText("Server started at " + new Date()+"\n");
   while(true){
    Socket socket = serverSocket.accept(); //程序会在这里阻塞,直到等到客户端连接
    clientNumber++;
    /*
    这里就是在界面中输出一些服务器、和连接的客户端信息
     */
    Platform.runLater(()->{
     ta.appendText("Starting thread for client " + clientNumber + " at " +
       new Date() +"\n");
     InetAddress inetAddress = socket.getInetAddress();
     ta.appendText("Client "+clientNumber + "'s host name is" +inetAddress.getHostName()
     +"\n");
     ta.appendText("Client"+clientNumber + "'s IP address is "+ inetAddress.getHostAddress()+"\n");
    });
    /*
    每有一个客户端连接服务器就创建一个线程,进行通信处理
     */
    new Thread(new HandleServer(socket)).start();
    try{
     Thread.sleep(100); //多个客户端连续快速连接服务器时,可能出现问题,这里设置延时
    }catch (InterruptedException e){
     e.printStackTrace();
    }
   }

}catch (IOException e){
   e.printStackTrace();
  }
 }
}

这一段代码主要作用就是循环等待客户端连接服务器:

Socket socket = serverSocket.accept();

在写这篇博客时,突然想知道阻塞的原理就去查了一下。。。。

然而并没有看懂。。这个应该涉及到操作系统层面,等之后把操作系统搞明白了在来补充吧。

3.服务器处理类HandleServer


class HandleServer implements Runnable {
 private Socket socket;
 private int name;
 private int toClientID;
 private DataOutputStream outputStream;
 private DataInputStream inputStream;
 public HandleServer(Socket socket){
  this.socket = socket;
  ServerTools.Tools().add(this);
  this.name = clientNumber;
 }
 @Override
 public void run() {
  try{
   inputStream = new DataInputStream(socket.getInputStream());
   outputStream = new DataOutputStream(socket.getOutputStream());
   outputStream.writeUTF("Your ID is:"+clientNumber);
   while (true){
    toClientID = inputStream.readInt();
    String messageGET = inputStream.readUTF();
    int err = ServerTools.Tools().MyWriteUTF(messageGET,toClientID); //MyWriteUTF 是一个自定义方法,serverTools.Tools()是一个工具类,一个静态对象。
    if (err==0){
     outputStream.writeUTF("No have this ID!");
    }
    Platform.runLater(()->{
     ta.appendText(socket.getInetAddress().getHostName()+" Message received from client:" + messageGET +"\n" );
    });
    System.out.println(clientNumber);
   }
  }catch (IOException e){
   clientNumber--;
   System.out.println(clientNumber);
   System.err.println("Client is closed!");
  }

}

这一块的代码主要就是创建输入输出数据流了

inputStream = new DataInputStream(socket.getInputStream());

outputStream = new DataOutputStream(socket.getOutputStream());

4.一些方法方便ServerTools类实现


 public void MyWriteUTF(String message){
  try {
   outputStream.writeUTF(message);
  } catch (IOException e) {
   ServerTools.Tools().remove(this);
   e.printStackTrace();
  }
 }

public int getName() {
  return name;
 }

二、ServerTools

1.实现指定服务器ID输出信息的工具


public class ServerTools {

private static final ServerTools servertools = new ServerTools();
public static ServerTools Tools(){
 return servertools;
}

Vector<MyServerSocket.HandleServer> vector = new Vector<MyServerSocket.HandleServer>();
public void add(MyServerSocket.HandleServer cs){
 vector.add(cs);
}
public void remove(MyServerSocket.HandleServer cs){
 vector.remove(cs);
}

public int MyWriteUTF(String message,int target) {
 for (int i = 0; i <= target; i++){
  try {
   if (vector.get(i).getName() == target) {
    MyServerSocket.HandleServer MSSHC = vector.get(i);
    MSSHC.MyWriteUTF(message);
    return 1;
   }
  }catch (ArrayIndexOutOfBoundsException e){
   e.printStackTrace();
   return 0;
  }
 }
 return 0;

}
}

vector用于保存客户端连接信息

一个粗糙的处理方式,逻辑上缺陷还很严重,主要我好像没找到这样的框架???

缺陷:因为服务器要返回客户端的ID让客户端将ID显示到交互界面,所以存在情况客户端多次连接断开后会使返回的ID出现重复

三、ClientSocket

1.同样的先建一个简单的界面用于输出信息和显示信息

JAVA实现SOCKET多客户端通信的案例

第一个编辑框就是 输入要发送指定客户端的ID 例如:1 或 2 这样的???

第二个编辑框就是 输入你要发送的信息了,很清楚

下面的就是显示框,嗯!


public class MyClientSocket extends Application {

private Socket socket;
private DataOutputStream toServer = null;
private DataInputStream fromServer = null;
private String ID;
private int targetID = 0;
private TextArea ta;

@Override
public void start(Stage primaryStage) throws Exception {
 BorderPane paneForTextField = new BorderPane();
 paneForTextField.setPadding(new Insets(5,5,5,5));
 paneForTextField.setStyle("-fx-border-color: green");
 paneForTextField.setLeft(new Label("Enter a Message:"));

TextField tf = new TextField();
 tf.setAlignment(Pos.BOTTOM_RIGHT);
 paneForTextField.setCenter(tf);

BorderPane ID_lable = new BorderPane();
 ID_lable.setPadding(new Insets(5,5,5,5));
 ID_lable.setStyle("-fx-border-color: green");
 ID_lable.setLeft(new Label("Enter a ID for send message:"));

TextField getId = new TextField();
 getId.setAlignment(Pos.BOTTOM_RIGHT);
 ID_lable.setCenter(getId);
 paneForTextField.setTop(ID_lable);

BorderPane mainPane = new BorderPane();
 ta = new TextArea();
 mainPane.setCenter(new ScrollPane(ta));
 mainPane.setTop(paneForTextField);

Scene scene = new Scene(mainPane,450,200);
 primaryStage.setTitle("SocketClient");
 primaryStage.setScene(scene);
 primaryStage.show();

tf.setOnAction(new EventHandler<ActionEvent>() {
  @Override
  public void handle(ActionEvent event) {
   targetID = Integer.parseInt(getId.getText().trim());
   if (targetID > 0 || targetID!=Integer.parseInt(ID));
   else return;
   try {
    String putMessage = tf.getText().trim();
    toServer.writeInt(targetID);
    toServer.writeUTF(putMessage);
    toServer.flush();
    ta.appendText("PUT message is :"+ putMessage +"\n");
    tf.setText("");
   }catch (IOException ex ){
    System.err.println(ex);
   }
  }
 });

try{
  socket = new Socket("localhost",8000);
  fromServer = new DataInputStream(socket.getInputStream());
  toServer = new DataOutputStream(socket.getOutputStream());
  ID = fromServer.readUTF();
  paneForTextField.setRight(new Label("Your ID is:"+ID));
  new Thread(new getMessage(socket,fromServer)).start();
 }catch (IOException ex){
  ta.appendText(ex.toString() +"\n");
 }
}
}

一样的要new一个Socket 去连接服务器,socket(),括号里的就是服务器的IP,和程序的端口号了,这种基于tcp协议的好像都是一个样???

2.创建一个线程用于循环获取信息并显示


class getMessage implements Runnable{
 private Socket socket;
 private DataInputStream formServer;
 public getMessage(Socket socket,DataInputStream formServer){
  this.socket = socket;
  this.formServer = formServer;
 }
 @Override
 public void run() {
  try {
   while (true) {
    String Message = formServer.readUTF();
    try{
     Thread.sleep(100);
    }catch (InterruptedException e) {
     e.printStackTrace();
    }
    ta.appendText("GET message from server is:" + Message + "\n");

}
  }catch (IOException e){
   System.err.println(e);
  }

}
}

很简单了,依旧是输入输出数据流,然后循环等待信息并输出。

3.新建一个TestClient类 这个类 和ClientSocket 一模一样 就是拿来测试的

JAVA实现SOCKET多客户端通信的案例

四、总结

java写socket 是真的简单!!!^_ ^!

JAVA实现SOCKET多客户端通信的案例

来源:https://blog.csdn.net/SDM_JH/article/details/85019236

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com