Java通过 Socket 实现 TCP服务端

 更新时间:2017年05月06日 16:53:35   投稿:lqh  
这篇文章主要介绍了Java通过 Socket 实现 TCP服务端的相关资料,需要的朋友可以参考下

1 Java Socket简介

  所谓socket 通常也称作”套接字“,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过”套接字”向网络发出请求或者应答网络请求。Socket和ServerSocket类库位于Java.NET包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。

2 TCPServer代码实例

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * TCP服务器端,单例模式
 * @author xiang
 *
 */
public class TCPServer implements Runnable {
  private static final Logger logger = LoggerFactory.getLogger(TCPServer.class);
  //成员变量/
  private static TCPServer serverInstance;      
  private static Map<String, SocketThread> socketMaps = new HashMap<String,SocketThread>();        //每个客户端连接时都会新建一个SocketThread与之对应  private static ServerSocket serverSocket;          //服务器套接字
  private static int serPort = 9999;              //服务器端口号
  private static boolean flag;                //服务器状态标志
  private static final int BUFFER_SIZE = 512;          //数据接收字符数组大小
  
  //构造函数/
  private TCPServer() {
    
  }
  
  /**
   * 获取实例
   * @return TCPServer实例serverInstance
   */
  public static TCPServer getServerInstance(){
    if(serverInstance==null)
      serverInstance = new TCPServer();
    return serverInstance;
  }
  
  /**
   * 开启服务器
   * @throws IOException
   */
  public void openTCPServer() throws IOException{    if(serverSocket==null || serverSocket.isClosed()){
      serverSocket = new ServerSocket(serPort);
      flag = true;
    }
  }
  
  /**
   * 关闭服务器
   * @throws IOException 
   */
  public void closeTCPServer() throws IOException{
    flag = false;   if(serverSocket!=null)
      serverSocket.close();
    /*for (Map.Entry<String, SocketThread> entry : socketMaps.entrySet()) { 
       System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());     
    } */ 
    for (SocketThread value : socketMaps.values()) 
      value.closeConnect();
    socketMaps.clear();    
  }
  
  /**
   * 服务器向客户端发送数据
   * @param bytes[]:待发送的字符数组
   * @param key 客户端的key,为空或""时表示数据群发
   * @throws IOException 
   */
  public void sendMessage(String key,byte[] msgBytes){
    if(key==null||key.equals("")){
      for (SocketThread value : socketMaps.values()) 
        value.sendMassage(msgBytes);
    }else{
      SocketThread thread = socketMaps.get(key);
      if(thread!=null)
        thread.sendMassage(msgBytes);
    }
  }
  
  /**
   * 服务器向客户端发送数据
   * @param key 客户端的key,为空或""时表示数据群发
   * @param msgStr:待发送的字符串
   * @throws IOException 
   */
  public void sendMessage(String key,String msgStr){   byte[] sendByte = msgStr.getBytes();
    if(key==null||key.equals("")){
      for (SocketThread value : socketMaps.values()) 
        value.sendMassage(sendByte);
    }else{
      SocketThread thread = socketMaps.get(key);
      if(thread!=null)
        thread.sendMassage(sendByte);
    }
  }
  
  @Override
  public void run() {
    logger.info("服务器线程已经启动");   while(true){
      try {
        while(flag){
          logger.info("服务器线程在监听状态中");
          Socket socket = serverSocket.accept();
          String key = socket.getRemoteSocketAddress().toString();
          SocketThread thread = new SocketThread(socket,key);
          thread.start();
          socketMaps.put(key, thread);          
          logger.info("有客户端连接:"+key);
        }        
      } catch (Exception e) {
        e.printStackTrace();        
      } 
    }
  }     
  
  /**
   * 处理连接后的数据接收请求内部类
   * @author xiang
   *
   */
  private class SocketThread extends Thread{
    private Socket socket;
    private String key;
    private OutputStream out;
    private InputStream in;
    
    //构造函数
    public SocketThread(Socket socket,String key) {
      this.socket = socket;
      this.key = key;
    }
    
    /**
     * 发送数据
     * @param bytes
     * @throws IOException 
     */
    public void sendMassage(byte[] bytes){
      try {
        if(out==null)
          out = socket.getOutputStream();
        out.write(bytes);
      } catch (Exception e) {
        e.printStackTrace();
        try {
          closeConnect();
        } catch (IOException e1) {
          e1.printStackTrace();
        }
        socketMaps.remove(key);        
      } 
    }

    /**
     * 关闭连接,释放资源
     * @throws IOException 
     */
    public void closeConnect() throws IOException{
      if(out!=null)  out.close();
      if(in!=null)  in.close();
      if(socket!=null && socket.isConnected())  socket.close();
    }
    
    @Override
    public void run() {
      byte[] receivBuf = new byte[BUFFER_SIZE];
      int recvMsgSize;
      try {
        in = socket.getInputStream();
        out = socket.getOutputStream();
        while ((recvMsgSize = in.read(receivBuf)) != -1) {
          String receivedData = new String(receivBuf, 0, recvMsgSize);
          System.out.println("Reverve form[port" + socket.getPort() + "]:" + receivedData);
          System.out.println("Now the size of socketMaps is" + socketMaps.size());
          /**************************************************************
           * 
           * 接收数据后的处理过程
           * 
           **************************************************************/
        }
        // response to client
        byte[] sendByte = "The Server has received".getBytes();
        // out.write(sendByte, 0, sendByte.length);
        out.write(sendByte);
        System.out.println("To Cliect[port:" + socket.getPort() + "] 回复客户端的消息发送成功");
        closeConnect();
        socketMaps.remove(key);        
      } catch (Exception e) {
        e.printStackTrace();
        try {
          closeConnect();
        } catch (IOException e1) {
          e1.printStackTrace();
        }
      }
    }
    
    //////////////
    public int getport(){
      return socket.getPort();
    }
  }
  //. end SocketThread  
}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

相关文章

  • 关于springboot中nacos动态路由的配置

    关于springboot中nacos动态路由的配置

    这篇文章主要介绍了springboot中nacos动态路由的配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • SpringBoot日志进阶实战之Logback配置经验和方法

    SpringBoot日志进阶实战之Logback配置经验和方法

    本文给大家介绍在SpringBoot中使用Logback配置日志的经验和方法,并提供了详细的代码示例和解释,包括:滚动文件、异步日志记录、动态指定属性、日志级别、配置文件等常用功能,覆盖日常Logback配置开发90%的知识点,感兴趣的朋友跟随小编一起看看吧
    2023-06-06
  • Java IO流对文件File操作

    Java IO流对文件File操作

    这篇文章主要介绍了Java IO流对文件File操作,java封装的一个操作文件及文件夹(目录)的对象。可以操作磁盘上的任何一个文件和文件夹
    2022-12-12
  • hutool实战:IoUtil 流操作工具类(将内容写到流中)

    hutool实战:IoUtil 流操作工具类(将内容写到流中)

    这篇文章主要介绍了Go语言的io.ioutil标准库使用,是Golang入门学习中的基础知识,需要的朋友可以参考下,如果能给你带来帮助,请多多关注脚本之家的其他内容
    2021-06-06
  • JAVA多线程实现的四种方式及使用场景详解

    JAVA多线程实现的四种方式及使用场景详解

    这篇文章主要介绍了JAVA多线程实现的四种方式及使用场景,并举例说明了在管理系统中多线程的应用场景,如数据导入导出、数据缓存更新、并发用户操作处理、系统监控和定时任务执行,需要的朋友可以参考下
    2025-01-01
  • 使用Backoff策略提高HttpClient连接管理的效率

    使用Backoff策略提高HttpClient连接管理的效率

    这篇文章主要为大家介绍了Backoff策略提高HttpClient连接管理的效率使用解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Java 阻塞队列BlockingQueue详解

    Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下
    2022-06-06
  • ConcurrentHashMap是如何实现线程安全的你知道吗

    ConcurrentHashMap是如何实现线程安全的你知道吗

    这篇文章主要介绍了ConcurrentHashMap是如何实现线程安全的你知道吗,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • JDBC自定义连接池过程详解

    JDBC自定义连接池过程详解

    这篇文章主要介绍了JDBC自定义连接池过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Java线程池7个参数的详细含义

    Java线程池7个参数的详细含义

    java多线程开发时,常常用到线程池技术,这篇文章是对创建java线程池时的七个参数的详细解释,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03

最新评论