基于socket的进程通信
2019-04-01 本文已影响0人
顾庭燎
-
实现目标
- 实现服务端与客户端的连接
- 实现多个客户端向服务端发送消息,并由服务端将消息发送给每个客户端
-
涉及的Java类
- java.net.ServerSocket 用于创建服务器端口
- java.net.Socket 用于创建Socket
- java.net.URLDecoder 用于在服务端将客户端传来的消息解码
- java.util.ArrayList 用于动态存放多个不同的Socket
- Java.util.scanner 用于从控制台读取输入
-
具体实现思路
-
服务端
-
在主函数中建立一个端口用于监听客户端请求,端口大小可自行设置
ServerSocket sock = new ServerSocket(1999)
-
需要接受多个客户端的消息,因此需要和每个客户端建立唯一的Socket对用于通信,所以需要将新建的Socket存入动态容器ArrayList<Socket>中
ArrayList<Socket> list = new ArrayList<Socket>()
-
使用while循环,在while循环中调用ServerSocket的accept()方法等待客户端请求,当接受到请求时就将返回的Socket存入容器中,并新建一个线程(调用start函数)
while(true) { Socket socket = sock.accept(); list.add(socket); new MsgThread(socket, list).start(); }
-
在线程类中进行数据的读入和输出
-
定义类的属性:Socket, ArrayList<Socket>,BufferedReader
-
定义构造函数,将传入的参数赋给当前对象的属性,同时,通过Socket读取客户端的数据到BufferedReader对象
BufferedReader bf = new BufferedReader(new InputStreamReader(client.getInputStream)); //这里需要用InputStreamReader类来包装client.getInputStream是为了将字节流转换成字符流
-
重载run函数,将读取的消息发送给除当前socket对象外的其他客户端
- 在这一步中的PrintWriter的使用要注意,一定要将自动刷新设置为true,否则消息就不能够即时传入到内存中,而是会等到程序结束时才传入,这个bug卡了我好久
-
将消息解码后显示在控制台上
-
-
客户端
-
和服务端差不多的思路,主要是实现消息的读取和上传
-
新建Socket,连接服务端
Socket client = new Socket("127.000.001", 1999;
-
读取Socket中的数据并显示在控制台上
-
线程函数和服务端类似,无非是从控制台读取数据然后用getOutPutStream写入Socket中
-
-
-
源码
//服务端 import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class ChatServer { //SockerList用于保存当前连接的用户 public static ArrayList<Socket> SocketList = new ArrayList<Socket>(); public static void main(String[] args) throws IOException { //创建端口监听用户的请求 ServerSocket sock = new ServerSocket(1999); System.out.println("服务启动...."); //服务器循环接受来自用户端的请求 while(true) { //等待客户端的请求,捕获到请求后返会一个Socket Socket socket = sock.accept(); System.out.println("服务连接...."); //将返回的Socket加入在线用户列表中 SocketList.add(socket); System.out.println("当前有" + (SocketList.size()) + "个用户"); //创建一个新的线程,每个连接都会有自己独立的任务线程,用于实现接受和发送消息 new MsgThread(socket, SocketList).start(); } } } //任务线程 class MsgThread extends Thread { //定义单个用户连接的Socket Socket client; //定义用户组的Socket ArrayList<Socket> clients; //定义读入的数据 BufferedReader br; //构造函数 public MsgThread(Socket client, ArrayList<Socket> clients) throws IOException { //调用父类的构造函数 super(); //使用传入的参数初始化 this.client = client; this.clients = clients; //将当前用户的输入缓存 br = new BufferedReader(new InputStreamReader(this.client.getInputStream())); } //重载run()函数,将接受到的用户信息发送给其他用户 @Override public void run() { try { String content = null; while(true) { //从某个客户端获取信息 if ((content = br.readLine()) != null) { //将消息发送给其他各个客户端 for (Socket socket:clients) { //去掉自身客户端 if (socket != client) { //将消息写入socket的缓存区,设置为自动刷新 PrintWriter pw = new PrintWriter(socket.getOutputStream(), true); pw.println(content); } } content = URLDecoder.decode(content, "UTF-8"); System.out.println(content); } } } catch (IOException e) { e.printStackTrace(); } } }
//客户端 import java.io.*; import java.net.*; public class ChatClient { public static void main(String[] args) throws Exception { //连接服务端 Socket client = new Socket("127.0.0.1", 1999); System.out.println("服务器已连接"); //新建线程 new MsgThread(client).start(); //获取输入 InputStream in = client.getInputStream(); BufferedReader bf = new BufferedReader(new InputStreamReader(in)); while (true) { String msg = bf.readLine(); //对收到的信息进行解码 msg=URLDecoder.decode(msg, "UTF-8"); System.out.println(msg); } } } class MsgThread extends Thread { Socket client; String hostname; public MsgThread(Socket client) { super(); this.client = client; try { //获取本计算机名称 InetAddress addr = InetAddress.getLocalHost(); hostname =addr.getHostName().toString(); } catch (UnknownHostException e1) { e1.printStackTrace(); } } //发送消息 @Override public void run() { try { //读取控制台输入 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //将客户端输出流存到pw中 PrintWriter pw = new PrintWriter(client.getOutputStream(),true); while (true) { String msg = br.readLine(); //对发出的消息进行编码 msg = URLEncoder.encode(hostname + "说:"+ msg, "UTF-8"); pw.println(msg); } } catch (IOException e) { e.printStackTrace(); } } }