Java多线程-----Socket通信

该博客介绍了一个基于Java的多线程Socket通信程序,包含Server和Client端。服务器端监听端口,有客户端连接时创建两个线程处理;客户端连接后也创建两个线程实现信息收发。程序基本通信正常,但存在一些bug,如客户端用Ctrl+C结束时服务器收到null,关闭部分客户端后线程未关闭等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

程序分Server和Client

服务器端打开侦听的端口,一有客户端连接就创建两个新的线程来负责这个连接

一个负责客户端发送的信息(ClientMsgCollectThread 类),

另一个负责通过该Socket发送数据(ServerMsgSendThread )

Server.java代码如下:

/*
 * 创建日期 2005-7-7
 *
 * TODO 要更改此生成的文件的模板,请转至
 * 窗口 - 首选项 - Java - 代码样式 - 代码模板
 */
package person.fane.MutiUser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务器端
 *
 * @author Fane
 */
public class Server extends ServerSocket {

 private static final int SERVER_PORT = 10000;

 /**
  * 构造方法,用于实现连接的监听
  *
  * @throws IOException
  */
 public Server() throws IOException {
  super(SERVER_PORT);

  try {
   while (true) {
    Socket socket = super.accept();

    new Thread(new ClientMsgCollectThread(socket), "getAndShow"
      + socket.getPort()).start();
    new Thread(new ServerMsgSendThread(socket), "send"
      + socket.getPort()).start();

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

 }

 public static void main(String[] args) throws IOException {
  new Server();
 }

 /**
  * 该类用于创建接收客户端发来的信息并显示的线程
  *
  * @author Fane
  * @version 1.0.0
  */
 class ClientMsgCollectThread implements Runnable {

  private Socket client;

  private BufferedReader in;

  private StringBuffer inputStringBuffer = new StringBuffer("Hello");

  /**
   * 得到Socket的输入流
   *
   * @param s
   * @throws IOException
   */
  public ClientMsgCollectThread(Socket s) throws IOException {
   client = s;

   in = new BufferedReader(new InputStreamReader(client
     .getInputStream(), "GBK"));
  }

  public void run() {
   try {

    while (!client.isClosed()) {
     inputStringBuffer.delete(0, inputStringBuffer.length());
     inputStringBuffer.append(in.readLine());

     System.out.println(getMsg(inputStringBuffer.toString()));
    }
   } catch (IOException e) {
    //e.printStackTrace();
    System.out.println(client.toString() + " is closed!");

   }
  }

  /**
   * 构造显示的字符串
   *
   * @param line
   * @return
   */
  private String getMsg(String line) {
   return client.toString() + " says:" + line;
  }

 }

 /**
  * 该类用于创建发送数据的线程
  *
  * @author Fane
  * @version 1.0.0
  */
 class ServerMsgSendThread implements Runnable {

  private Socket client;

  private PrintWriter out;

  private BufferedReader keyboardInput;

  private StringBuffer outputStringBuffer = new StringBuffer("Hello");

  /**
   * 得到键盘的输入流
   *
   * @param s
   * @throws IOException
   */
  public ServerMsgSendThread(Socket s) throws IOException {
   client = s;

   out = new PrintWriter(client.getOutputStream(), true);
   keyboardInput = new BufferedReader(new InputStreamReader(System.in));

  }

  public void run() {
   try {

    while (!client.isClosed()) {
     outputStringBuffer.delete(0, outputStringBuffer.length());
     outputStringBuffer.append(keyboardInput.readLine());

     out.println(outputStringBuffer.toString());
    }
   } catch (IOException e) {
    //e.printStackTrace();
    System.out.println(client.toString() + " is closed!");

   }
  }

 }

}

客户端:

实现基于IP地址的连接,连接后也创建两个线程来实现信息的发送和接收

/*
 * 创建日期 2005-7-7
 *
 */
package person.fane.MutiUser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * 客户端
 *
 * @author Fane
 */
public class Client {

 private Socket mySocket;

 /**
  * 创建线程的构造方法
  *
  * @param IP
  * @throws IOException
  */
 public Client(String IP) throws IOException {

  try {
   mySocket = new Socket(IP, 10000);
   new Thread(new ServerMsgCollectThread(mySocket), "getAndShow"
     + mySocket.getPort()).start();
   new Thread(new ClientMsgSendThread(mySocket), "send"
     + mySocket.getPort()).start();

  } catch (IOException e) {
   //e.printStackTrace();
   System.out.println("Server.IP:" + IP
     + " port:10000 can not be Connected");
  }
 }

 public static void main(String[] args) throws IOException {
  try {
   new Client(args[0]);
  } catch (Exception e) {
   System.out.println("输入的IP地址错误");
  }
 }

 /**
  * 该类用于创建接收服务端发来的信息并显示的线程
  *
  * @author Fane
  * @version 1.0.0
  */
 class ServerMsgCollectThread implements Runnable {

  private Socket client;

  private BufferedReader in;

  private StringBuffer inputStringBuffer = new StringBuffer("Hello");

  /**
   * 得到Socket的输入流
   *
   * @param s
   * @throws IOException
   */
  public ServerMsgCollectThread(Socket s) throws IOException {
   client = s;

   in = new BufferedReader(new InputStreamReader(client
     .getInputStream(), "GBK"));
  }

  public void run() {
   try {

    while (!client.isClosed()) {
     inputStringBuffer.delete(0, inputStringBuffer.length());
     inputStringBuffer.append(in.readLine());
     System.out.println(getMsg(inputStringBuffer.toString()));
    }
   } catch (IOException e) {
    //e.printStackTrace();
    System.out.println(client.toString() + " is closed!");
    System.exit(0);
   }
  }

  /**
   * 构造输入字符串
   *
   * @param line
   * @return
   */
  private String getMsg(String line) {
   return client.toString() + " says:" + line;
  }

 }

 /**
  * 该类用于创建发送数据的线程
  *
  * @author Fane
  * @version 1.0.0
  */
 class ClientMsgSendThread implements Runnable {

  private Socket client;

  private PrintWriter out;

  private BufferedReader keyboardInput;

  private StringBuffer outputStringBuffer = new StringBuffer("Hello");

  /**
   * 得到键盘的输入流
   *
   * @param s
   * @throws IOException
   */
  public ClientMsgSendThread(Socket s) throws IOException {
   client = s;

   out = new PrintWriter(client.getOutputStream(), true);
   keyboardInput = new BufferedReader(new InputStreamReader(System.in));

  }

  public void run() {
   try {

    while (!client.isClosed()) {
     outputStringBuffer.delete(0, outputStringBuffer.length());
     outputStringBuffer.append(keyboardInput.readLine());

     out.println(outputStringBuffer.toString());
    }
    out.println("--- See you, bye! ---");
   } catch (IOException e) {
    //e.printStackTrace();
    System.out.println(client.toString() + " is closed!");
    System.exit(0);
   }
  }

 }

}

该程序基本通信没有问题

但是有如下bug,请各位提出宝贵意见

1:在cmd模式下,用Ctrl+C来结束客户端程序,服务器先出现收到为null,再出现断开连接的提示,在直接关闭命令行时就只提示断开连接,不知道这个null何来

Socket[addr=/192.168.0.12,port=2205,localport=10000] says:null
Socket[addr=/192.168.0.12,port=2205,localport=10000] is closed!

2:假如打开5个命令行并连接成功后,发送信息时,服务器能收到所有5个客户端来的信息,但是5个客户端只能轮流收到服务器的信息,也就是说我每打一个"Hello"+Enter,只有一个客户端能收到消息,重复5次,这样每个客户端都能收到一次,这个本不奇怪(设计的问题,不好意思),但是我关闭了其中4个以后,还是要发5次客户端才能收到一次消息,也就是说其他4个Socket关闭了,但是线程没有关闭,不知道怎样才能解决线程的这个问题(在一台机子上试验出现这个问题)

发送:

Socket[addr=/192.168.0.12,port=2201,localport=10000] is closed!
Socket[addr=/192.168.0.12,port=2203,localport=10000] says:null
Socket[addr=/192.168.0.12,port=2203,localport=10000] is closed!
Socket[addr=/192.168.0.12,port=2204,localport=10000] says:null
Socket[addr=/192.168.0.12,port=2204,localport=10000] is closed!
Socket[addr=/192.168.0.12,port=2205,localport=10000] says:null
Socket[addr=/192.168.0.12,port=2205,localport=10000] is closed!

hehhe
hehe
hehe
hehe
hehe

接收:Socket[addr=/192.168.0.12,port=10000,localport=2206] says:hehe

(前面4个hehe丢失了)

其它bug也在查找中.......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值