JAVA實現(xiàn)SOCKET多客戶端通信的案例
一、ServerSocket
1.為了方便調(diào)試,先創(chuàng)建一個界面用于顯示客戶端連接信息

基于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(); //創(chuàng)建線程啟動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");
});
/*
每有一個客戶端連接服務器就創(chuàng)建一個線程,進行通信處理
*/
new Thread(new HandleServer(socket)).start();
try{
Thread.sleep(100); //多個客戶端連續(xù)快速連接服務器時,可能出現(xiàn)問題,這里設置延時
}catch (InterruptedException e){
e.printStackTrace();
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}
這一段代碼主要作用就是循環(huán)等待客戶端連接服務器:
Socket socket = serverSocket.accept();
在寫這篇博客時,突然想知道阻塞的原理就去查了一下。。。。
然而并沒有看懂。。這個應該涉及到操作系統(tǒng)層面,等之后把操作系統(tǒng)搞明白了在來補充吧。
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()是一個工具類,一個靜態(tài)對象。
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!");
}
}
這一塊的代碼主要就是創(chuàng)建輸入輸出數(shù)據(jù)流了
inputStream = new DataInputStream(socket.getInputStream());
outputStream = new DataOutputStream(socket.getOutputStream());
4.一些方法方便ServerTools類實現(xiàn)
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.實現(xiàn)指定服務器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出現(xiàn)重復
三、ClientSocket
1.同樣的先建一個簡單的界面用于輸出信息和顯示信息

第一個編輯框就是 輸入要發(fā)送指定客戶端的ID 例如:1 或 2 這樣的???
第二個編輯框就是 輸入你要發(fā)送的信息了,很清楚
下面的就是顯示框,嗯!
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協(xié)議的好像都是一個樣???
2.創(chuàng)建一個線程用于循環(huán)獲取信息并顯示
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);
}
}
}
很簡單了,依舊是輸入輸出數(shù)據(jù)流,然后循環(huán)等待信息并輸出。
3.新建一個TestClient類 這個類 和ClientSocket 一模一樣 就是拿來測試的

四、總結
java寫socket 是真的簡單?。?!^_ ^!

以上這篇JAVA實現(xiàn)SOCKET多客戶端通信的案例就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Java自帶定時任務ScheduledThreadPoolExecutor實現(xiàn)定時器和延時加載功能
今天小編就為大家分享一篇關于Java自帶定時任務ScheduledThreadPoolExecutor實現(xiàn)定時器和延時加載功能,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12
IntelliJ Idea 2020.1 正式發(fā)布,官方支持中文(必看)
這篇文章主要介紹了IntelliJ Idea 2020.1 正式發(fā)布,官方支持中文了,本文通過截圖的形式給大家展示,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04

