Java-Socket服务端和多个客户端长连接

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/P923284735/article/details/89177671

Socket

建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。

短连接

服务端和客户端建立连接后,客户端获取流来和服务端通讯,通讯完毕后,关闭流,关闭Socket连接。

长连接

服务端和客户端建立连接后,客户端获取流来和服务端通讯,通讯完毕不关闭流,不关闭Socket,一直保持着通讯。

服务端代码

Socket服务端启动线程:

package com.jeesite.modules.socket;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 * @Desc 服务端线程
 * @author PGQing
 * 
 */
public class SocketServerThread implements Runnable {

	private static final int PORT = 8989;
	private static final String CHARSET = "UTF-8";
	List<Socket> sockets = new ArrayList<>();
	ServerSocket server = null;

	public SocketServerThread() {
		try {
			server = new ServerSocket(PORT);
			System.out.println("Socket服务启动成功~");
		} catch (IOException e) {
			System.out.println("初始化Socket服务异常:\n");
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		try {
			while (true) {
				// 建立socket接口,accept方法等到用户连接才会继续执行
				Socket socket = server.accept();
				socket.setKeepAlive(true);
				// 在服务器显示连接的电脑
				String message = socket.getInetAddress().getHostAddress().toString();
				System.out.println("客户端:" + message + "已连接~");
				// 将已有的连接添加到集合中
				sockets.add(socket);
				// 向客户端发送登录信息
				SendMessageToClient(message);
				// 建立读取客户端数据的线程
				Thread t = new Thread(new ReadClientDataThread(socket));
				t.start();
			}
		} catch (Exception e) {
			System.out.println("Socket运行中出现了异常:\n");
			e.printStackTrace();
		}
	}

	public void SendMessageToClient(String message) {
		// 遍历集合,寻找已经链接的客户端
		for (Socket s : sockets) {
			// 判断是否已经连接
			if (null != s && s.isConnected()) {
				try {
					OutputStream os = s.getOutputStream();
					os.write(message.getBytes(CHARSET));
					os.flush();
				} catch (Exception e) {
					System.out.println("Socket服务向客户端发送数据出现了异常:\n");
					e.printStackTrace();
				}
			}
		}
	}

}

Socket建立通讯后的读取数据线程:

package com.jeesite.modules.socket;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import com.jeesite.modules.utils.HttpUtils;

/**
 * @Desc 读取客户端数据的线程
 * @author PGQing
 *
 */
public class ReadClientDataThread implements Runnable {
	private InputStream is = null;

	public ReadClientDataThread(Socket socket) {
		try {
			is = socket.getInputStream();
		} catch (IOException e) {
			System.out.println("获取已连接会话中的输入流出现了错误:\n");
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		try {
			int len = 0;
			byte[] bytes = new byte[1024];
			String temp = null;
			while ((len = is.read(bytes))!=-1) {
				temp = new String(bytes, 0, len);
				// 发送GPS信息请求
				Map<String, String> map = new HashMap<>();
				map.put("param", temp);
				HttpUtils.send("http://localhost:8085/jyzs/socket/saveInfo", map, 10);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

线程启动,拿Spring Boot 为示例:

@SpringBootApplication
public class Application{
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        //线程启动
        Thread mainThread = new Thread(new SocketServerThread());
        mainThread.start();
    }
}

猜你喜欢

转载自blog.csdn.net/P923284735/article/details/89177671