一、ServerSocket
1.为了方便调试,先创建一个界面用于显示客户端连接信息
基于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; } Vectorvector = new Vector (); 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.同样的先建一个简单的界面用于输出信息和显示信息
第一个编辑框就是 输入要发送指定客户端的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() { @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多客户端通信的案例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。