热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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

这篇文章主要介绍了JAVA实现SOCKET多客户端通信的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

一、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;
 }

 Vector vector = 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多客户端通信的案例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。


推荐阅读
  • 本指南详细介绍了如何在同一台计算机上配置多个GitHub账户,并使用不同的SSH密钥进行身份验证,确保每个账户的安全性和独立性。 ... [详细]
  • 在Linux系统上构建Web服务器的详细步骤
    本文详细介绍了如何在Linux系统上搭建Web服务器的过程,包括安装Apache、PHP和MySQL等关键组件,以及遇到的一些常见问题及其解决方案。 ... [详细]
  • Redis安全防护深入解析
    本文详细探讨了如何通过指令安全、端口管理和SSL代理等措施有效保护Redis服务的安全性。 ... [详细]
  • 全能终端工具推荐:高效、免费、易用
    介绍一款备受好评的全能型终端工具——MobaXterm,它不仅功能强大,而且完全免费,适合各类用户使用。 ... [详细]
  • 本文将详细探讨 Linux 系统中的 netstat 命令,该命令用于查看网络状态和连接情况。通过了解 IP 地址和端口的基本概念,我们将更好地理解如何利用 netstat 命令来监控和管理网络服务。 ... [详细]
  • 本文详细介绍了Linux操作系统中的cp和scp命令,包括它们的基本使用方法、常见选项以及如何通过scp命令安全地在不同主机之间传输文件。 ... [详细]
  • 本文介绍了MySQL数据库的安全权限管理思想及其制度流程,涵盖从项目开发、数据库更新到日常运维等多个方面的详细流程控制,旨在通过严格的流程管理和权限控制,有效预防数据安全隐患。 ... [详细]
  • 在Java应用程序开发过程中,FTP协议被广泛用于文件的上传和下载操作。本文通过Jakarta Commons Net库中的FTPClient类,详细介绍如何实现文件的上传和下载功能。 ... [详细]
  • 本文详细介绍了如何通过Git Bash在本地仓库与远程仓库之间建立连接并进行同步操作,包括克隆仓库、提交更改和推送更新等步骤。 ... [详细]
  • Windows 环境下安装 Git 并连接 GitHub 的详细步骤
    本文详细介绍了如何在 Windows 系统中安装 Git 工具,并通过配置 SSH 密钥实现与 GitHub 的安全连接。包括下载、安装、环境配置及验证连接等关键步骤。 ... [详细]
  • Django xAdmin 使用指南(第一部分)
    本文介绍如何在Django项目中集成和使用xAdmin,这是一个增强版的管理界面,提供了比Django默认admin更多的功能。文中详细描述了集成步骤及配置方法。 ... [详细]
  • 本文介绍了Java语言开发的远程教学系统,包括源代码、MySQL数据库配置以及相关文档,适用于计算机专业的毕业设计。系统支持远程调试,采用B/S架构,适合现代教育需求。 ... [详细]
  • 首先我是刚接触JAVA,为了学JAVA,我在自己买了一本《精通Java-JDK、数据库系统开发、Web开发》王晓悦编著。书的内容我已经看完了,代码也亲自敲了一遍。但是还是觉得深入不进去,下一步在看什么 ... [详细]
  • Linux环境下Git安装及常见问题解析
    本文详细介绍了在Ubuntu系统中安装Git的过程,包括环境检查、软件安装、用户配置以及SSH密钥生成等步骤,并针对安装过程中可能出现的问题提供了有效的解决方案。 ... [详细]
  • 本文档详细介绍了思科交换机的基本配置命令,包括进入特权模式、配置交换机名称及密码、VLAN配置、端口访问、查看配置信息、恢复出厂设置以及远程登录设置等。 ... [详细]
author-avatar
TzXh爱是生活
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有