IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Java 使用Socket实现简易聊天室(新手控制台版) -> 正文阅读

[网络协议]Java 使用Socket实现简易聊天室(新手控制台版)

一.服务器端思路整理

? ? ? ? 想要实现聊天室,对于服务器端由于需要一直监听用户的连接以及用户的消息发送,所以需要多线程来为每一个用户分配一个线程来实现功能。

实现start方法,创建serverSocket链接,死循环用以监听客户端用户的链接,当一个用户链接之后,就为其新开一个线程。通过这个新开的线程来实现对每个用户的功能。

public void start() throws IOException {
		ServerSocket server = new ServerSocket(8888);
		while(true) {
			Socket socket = server.accept();
			System.out.println(socket.getInetAddress().getHostAddress()+"正在链接!!!");
			ThreadSocket client = new ThreadSocket(socket);
			new Thread(client).start();
		}
	}

创建一个成员变量用来储存每一个用户的线程:

List<ThreadSocket> clients = new ArrayList<ThreadSocket>();

?我是创建了一个线程内部类,方便我直接使用这个线程数组,因为在一个用户登录的时候,服务器会给每一个用户广播一条欢迎消息,每个用户连接只有一次,所以我选择在线程的构造函数中将此线程添加到线程数组,并执行广播方法send(),此方法通过遍历线程数组,给每个线程的socket添加输出流,推送欢迎消息

public class ThreadSocket implements Runnable{
		
		Socket socket;
		String name;
		public ThreadSocket(Socket socket) throws IOException {			
			this.socket = socket;
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		    name = br.readLine();
		    String welcome = name+"["+socket.getInetAddress().getHostAddress()+"]来到了房间";
		    clients.add(this);
		    send(welcome);
		    System.out.println(welcome);
		}


		private void send(String welcome) throws IOException {
			for (ThreadSocket c : clients) {
				BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(c.socket.getOutputStream()));
			    bw.write(welcome);
			    bw.newLine();
			    bw.flush();		
			}
		}
		
	}

单独讲此线程的run方法:由于用户发送消息需要服务器一直监听,等待接受,所以必须写在死循环中,需要同客户端约定一个退出方式,因为一旦一方关闭,另一方socket.getInputStream()就会接受不到,此时程序会不断循环输出异常。

public void run() {
			while(true) {
				BufferedReader br;
				try {
					br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
					String msg = br.readLine();
					String name1 = name+"["+socket.getInetAddress().getHostAddress()+"]";
					if(msg.equals("byebye")) {
						System.out.println(name1+"离开了聊天室");
						send(name1+"离开了聊天室");
						clients.remove(this);
						socket.close();
						break;
					}
					send(name1+":"+msg);
				    System.out.println(name1+":"+msg);
				} catch (IOException e) {
					e.printStackTrace();
				}
			    
			}
		}

主方法:通过对象调用非静态方法

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

二.客户端

主要注意的就是客户端与服务器端的发送接受关系,必须一一对应好,同样,客户端单线程实现不了一直监听服务器推送信息以及一直监听用户发送信息,在规定的退出指令中,需要注意当客户端输入推出指令后,客户端等待服务器推送的消息的线程仍在等待,所以我让服务器给本人也推送一个退出信息,不然也会爆出异常。

public class Client {
	
	public static void main(String[] args) {
		Socket socket=null;
		try {
			socket = new Socket("10.7.184.72",8888);
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
		    System.out.println("请输入用户名:");
		    Scanner sc = new Scanner(System.in);
			bw.write(sc.next());
		    bw.newLine();
		    bw.flush();
		    BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		    System.out.println(br.readLine());
			ClientThread clientThread = new ClientThread(socket);
			clientThread.start();
			while(true) {
			    System.out.print("请输入发送的内容:");
			    String input = sc.next();
				bw.write(input);
				bw.newLine();
			    bw.flush();	
			    if(input.equals("byebye")) {
					clientThread.interrupt();
			    	break;
			    }
			}
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		
	}
	
}

客户端新开线程类:当用户输入退出指令后,while循环判定为false,但是此时线程还在br = new BufferedReader(new InputStreamReader(socket.getInputStream()));等待消息,所以跟服务器的关系发送要对应好。

class ClientThread extends Thread{
	Socket socket;
	public ClientThread(Socket socket) {
		this.socket=socket;
	}
	
	@Override
	public void run() {
		while (!Thread.interrupted()) {
			BufferedReader br;
			try {
				br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			    System.out.println(br.readLine());
			} catch (IOException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
		}
	}
}

三.运行截图:

服务器端:

客户端:

?

?

此为新手向简易聊天室,大家有什么问题和建议,欢迎提出,大家一起讨论。

?

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 12:18:17  更:2021-09-03 12:18:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:41:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码