关于java多线程socket问题

发布于 2021-11-08 01:40:03 字数 5287 浏览 914 评论 18

我写了一个java 多线程socket,能够运行,是服务器每3秒能够接受10次一个客户端发送的信息,当打开第二个客户端时就不行,提示端口已被占用。但我想实现的是 一个服务器能够监听10个不同客户端,有一个客户端掉线就能够通过服务器通知其他客户端。求高手指教,怎么把每个客户端当成一个线程,服务器端口被占用的问题如何解决?下面是代码。

服务器端

import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.net.*;
 import java.util.concurrent.*;
 public class MultiThreadServer {
  static int workThreadNum = 0;
     private ServerSocket serverSocket;
     private ExecutorService executorService;//线程池
     private final int POOL_SIZE=10;//单个CPU线程池大小
     private int port=8821;
     private static final String SERVER = "192.168.1.109";
     public void service() throws IOException{
      serverSocket=new ServerSocket(port);
         executorService=Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*POOL_SIZE);
         if (serverSocket == null) 
        {
           System.out.println("创建ServerSocket失败!");
           return;
         }
         while(true){
             Socket socket=null;
             try {
                 //接收客户连接,只要客户进行了连接,就会触发accept();从而建立连接
                 socket=serverSocket.accept();
                 executorService.execute(new Handler(socket));
                 
            } catch (Exception e) {
                 e.printStackTrace();
             }
         }
     }

 public ServerSocket startListenUserReport(int port) {
   try {
    ServerSocket serverSocket = new ServerSocket();
    if (!serverSocket.getReuseAddress()) {
     serverSocket.setReuseAddress(true);
    }
    serverSocket.bind(new InetSocketAddress(SERVER, port));
    System.out.println("开始在" + serverSocket.getLocalSocketAddress()
      + "上侦听用户的心跳包请求!");
    return serverSocket;
   } catch (IOException e) {
    System.out.println("端口" + port + "已经被占用!");
    if (serverSocket != null) {
     if (!serverSocket.isClosed()) {
      try {
       serverSocket.close();
      } catch (IOException e1) {
       e1.printStackTrace();
      }
     }
    }
   }
   return serverSocket;
  }

class Handler implements Runnable {
    private Socket socket;

   /**
     * 构造函数,从调用者那里取得socket
     * 
    */
    public Handler(Socket socket) {
     this.socket = socket;
    }

   public void run() {
     
    try {
      workThreadNum = workThreadNum + 1;
      System.out.println("第" + workThreadNum + "个的连接:" + socket.getInetAddress() + ":" + socket.getPort());
      while (true) {
       try {
    ObjectInputStream ois = new ObjectInputStream(
       new BufferedInputStream(socket.getInputStream()));
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
       
     }
     
     //System.out.println("用户已经断开连接!");
     } finally {
      if (socket != null) {
       try {
        // 断开连接
        socket.close();
       } catch (IOException e) {
        e.printStackTrace();
       }
      }
     }
    }
    }
 }

客户端

import java.io.IOException;
 import java.io.ObjectOutputStream;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.net.UnknownHostException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 public class MultiThreadClient {
     public void ThreadClient() {
         int numTasks = 10;
         
        ExecutorService exec = Executors.newCachedThreadPool();

        for (int i = 0; i < numTasks; i++) {
             exec.execute(createTask(i));
         }
     }

    
//定义一个任务

   private static Runnable createTask(final int taskID) {
         return new Runnable() {
           Socket server;
             public void run() {
                 System.out.println("Task " + taskID + ":start");
                 try {
      server = new Socket(InetAddress.getLocalHost(), 8821);
     } catch (UnknownHostException e) {
      
      e.printStackTrace();
     } catch (IOException e) {
      
      e.printStackTrace();
     }
                 while (true) {
                  ObjectOutputStream out=null;
     try {
      out = new ObjectOutputStream(server.getOutputStream());
     } catch (IOException e) {
      
      e.printStackTrace();
     }
                  try {
      out.writeObject(HRip.getHostIP());
     } catch (IOException e) {
      
      e.printStackTrace();
     }
                  try {
      out.flush();
     } catch (IOException e) {
      
      e.printStackTrace();
     }
                  try {
      Thread.sleep(3000);
     } catch (InterruptedException e) {
      
      e.printStackTrace();
     }
                 }            }

        };
     }
 }
  class  NodeSever implements Runnable{

   MultiThreadServer client = null;

  private boolean stoped = false;

  private int interval = 1000;

  public NodeSever() {
   }

  public MultiThreadServer getNodeClient() {
    if (client == null) {
     client = new MultiThreadServer();
    }
    return client;
   }

  public void run() {
    while (!stoped) {
     try {
      NodeClient.send();
      synchronized (this) {
       this.wait(interval);
      }
     } catch (Exception e) {
     }
    }
   }

  public void destroy() {
    stoped = true;
    synchronized (this) {
     this.notify();
    }
   }
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

月牙弯弯 2021-11-10 18:22:34

引用来自“美女你的砖头掉了”的答案

我想问题是  你分别new了2个不同的ServerSocket对象 所以绑定失效  没必要写bind()..和ss = null这样的代码  2个步骤恰好被java虚拟机自己执行了 SS对象本身就是一个进程不是线程 不同端口下的进程之间做不到你所说的广播消息效果 因为不在同一个进程 

而一个socket是main进程的子进程  要做动态广报 很容易想到计数器原理 起一个 staic int counter 在main主线程里 再起一个子进程1秒检测一次counter值 小于10就在你封装的<t>sockets向量里迭代write()就可以了  不过要用到向量 估计比较麻烦

回忆凄美了谁 2021-11-10 18:22:34

谢谢你,我已经解决了

情栀口红 2021-11-10 18:22:34

use mina

归途 2021-11-10 18:22:34

你的问题怎么解决的啊!我现在遇到这样的一个问题,第一次启动 tomcat通讯成功! 第二次就没有反映,要重新启动tomcat  悲剧死里,那个大哥大姐知道不

倾城泪 2021-11-10 18:22:34

当然不是哦! 就是第一次服务器给客户端传数据没有问题,第二次就有问题了,java.net.SocketTimeoutException: Read timed out

情栀口红 2021-11-10 18:22:34

什么意思?写个死循环。

筱果果 2021-11-10 18:22:34

也是用的java socket

 

躲猫猫 2021-11-10 18:22:34

Socket server = new Socket(ip,8821); ip是服务器端的IP

已下线请稍等 2021-11-10 18:22:34

而且第一次断点就服务器! 第二次 好像什么反映都没有

 

够钟 2021-11-10 18:22:33

嗯。我发现了。现在主要的问题是怎么使一个服务器用自定义的端口接受多个客户端发送的信息,当第二个、第三个客户端启动时不会被提示端口被占用呢?

已下线请稍等 2021-11-10 18:22:25

我想问题是  你分别new了2个不同的ServerSocket对象 所以绑定失效  没必要写bind()..和ss = null这样的代码  2个步骤恰好被java虚拟机自己执行了 SS对象本身就是一个进程不是线程 不同端口下的进程之间做不到你所说的广播消息效果 因为不在同一个进程 

而一个socket是main进程的子进程  要做动态广报 很容易想到计数器原理 起一个 staic int counter 在main主线程里 再起一个子进程1秒检测一次counter值 小于10就在你封装的<t>sockets向量里迭代write()就可以了  不过要用到向量 估计比较麻烦

天涯离梦残月幽梦 2021-11-10 18:21:17

sorry,这个不是我想要的

等你爱我 2021-11-10 18:21:16

我想要的是一个服务器对应多个客户端

苍暮颜 2021-11-10 18:16:48

因为服务器要接受多个客户端发送的信息,接受socket套字节的不就一个端口吗?那个端口不是自己定义,然后所有客户端都向这个端口发送吗?还是怎样?

情栀口红 2021-11-10 17:43:46

是这样。你需要一个ServerSocket势力 我也没看到你Server的Main函数,不知道你调用的逻辑是怎样的

落墨 2021-11-10 15:15:51

这个程序我是放在Web项目里运行的,不需要主函数,只要在其他类里调用这个两个方法就行。先调用的服务端方法,然后调用的客户端方法。

孤檠 2021-11-10 07:28:47

在我看来你只需要service方法就够了,另一个方法是多余的。所谓连接多个客户端,是用客户端Socket区分的,服务器端你只需要一个ServerSocket实例

可是我不能没有你 2021-11-10 01:18:13

你在service和
startListenUserReport两个方法里 分别新建了ServerSocket绑定了同样的端口

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文