Java Socket 多线程聊天室
本来这次作业我是想搞个图形界面的,然而现实情况是我把题意理解错了,于是乎失去了最初的兴致,还是把程序变成了功能正确但是“UI”不友好的console了,但是不管怎么样,前期的图形界面的开发还是很有收获的,毕竟讲真,想要把Java搞得有形有色的也是很不容易的,借助可视化的插件windowsBuilder,这个过程还是既exciting 又tiring的。
好吧 ,然而图形界面已经成为了历史,现在来说说这个功能正确的console 吧
我也是刚知道的Eclipse里面是可以跑好多个程序的,只要你的一个.java文件中有public static void main,他就能给你一个窗口,让你跑起来。只不过这些窗口堆叠在一起,需要自行选择不同的窗口进行IO操作。
总的思路是采用c/s的方式,client借助socket完成向server的发送和接受两个工作,当然了,为了体现出真实情况下的双工的特点,发送和接受是需要开两个线程的,也就是说,一个用户需要自己管理两个线程。server则相对来讲比较复杂,因为这里面涉及到了调度,server需要有发送消息给在线client的线程(这个线程要做的事情就是只要有消息就要把消息发到所有的用户的窗口),以及接受client发来的消息的线程(这个线程要做的事情就是将接收到的消息全部交给发送消息的线程,于是这两个线程之间的通信问题也是实现上的一个关键~),为了使得所有的用户消息是同步的,server需要管理一个用户线程的列表,用以实现用户的行为的控制,于是乎这就要求只要有用户请求连接服务器,服务器就要为用户新建一个线程,那么client 和server 之间靠什么来进行联系呢,那就是我们的socket了。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket; public class Client extends Thread{ private static String serverIp = "127.0.0.1";
private static int serverPort = 8001; private Socket clientsSocket; //plays key role
private PrintWriter pw; // for send data
private BufferedReader br; // for receive data public Client(){
try {
clientsSocket = new Socket(serverIp, serverPort);
pw = new PrintWriter(clientsSocket.getOutputStream(),true);
br = new BufferedReader(new InputStreamReader(clientsSocket.getInputStream()));
new readServer(); while(true){
br = new BufferedReader(new InputStreamReader(System.in));
String input = br.readLine();
//System.out.println("this is the input :" + input);
pw.println(input);
}
} catch (Exception e) {
e.printStackTrace();
}
} class readServer extends Thread{
private BufferedReader reader; public readServer(){
try {
reader = new BufferedReader(new InputStreamReader(clientsSocket.getInputStream()));
start();
} catch (Exception e) {
e.printStackTrace();
}
} public void run(){
try {
while(true){
String content = reader.readLine();
if(content.equals("bye Client")){
break;
}
else {
System.out.println(content);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
} public static void main(String[] args) throws Exception{
new Client();
}
}
Client codes
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedList; public class Server { private static int port = 8001;
private static boolean prit = false;
private static ArrayList<String> userList = new ArrayList<>();
private static LinkedList<String> messageList = new LinkedList<>();
private static ArrayList<ServerThread> threadsList = new ArrayList<>(); private ServerSocket serverSocket; public Server(){
try {
serverSocket = new ServerSocket(port);
new PrintClient(); while(true){
Socket socket = serverSocket.accept();
new ServerThread(socket);
}
} catch (Exception e) {
e.printStackTrace();
}
} class PrintClient extends Thread{
public PrintClient(){
start();
} public void run(){
while(true){
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
if (prit == true){
String msg = messageList.getFirst();
//System.out.println("prepare to sent to Clent");
for (ServerThread sThread : threadsList){
sThread.sendMessage(msg);
}
synchronized (messageList) {
messageList.removeFirst();
}
prit = messageList.size() > 0 ? true : false;
}
}
}
} class ServerThread extends Thread{
private Socket client;
private PrintWriter pw;
private BufferedReader br;
private String user; public ServerThread(Socket socket){
try {
client = socket;
pw = new PrintWriter(client.getOutputStream(),true);
br = new BufferedReader(new InputStreamReader(client.getInputStream()));
br.readLine(); pw.println("connect success input your name ~");
start();
} catch (Exception e) {
e.printStackTrace();
}
} public void pushMessage(String msg){
synchronized (messageList) {
messageList.add(msg);
}
prit = true;
} public void sendMessage(String msg){
pw.println(msg);
} public void run(){
try {
int first = 1;
String msg = br.readLine();
while(!msg.equals("bye")){
if (first == 1){
user = msg;
userList.add(user);
threadsList.add(this);
pw.println(user + " hello you can chat now ");
this.pushMessage("Client <" + user + "> " + "join in ~");
//System.out.println("the prit is " + prit);
first--;
}
else {
this.pushMessage("Client<" + user + "> "+ "say :" + msg);
//System.out.println("the prit is " + prit + " " + messageList.size());
}
msg = br.readLine();
//System.out.println(msg);
}
pw.println("bye Client");
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
client.close();
} catch (Exception e2) {
e2.printStackTrace();
}
threadsList.remove(this);
userList.remove(user);
pushMessage(user + " leave ~");
}
}
} public static void main(String[] srgs) throws Exception{
new Server();
}
}
Server codes
在这里注意一个问题,server端的PrintClient线程在run的过程中一定要有sleep的过程,否则会因为一开始的prit设置为false而在一直在while(true)的死循环中得不到更新,也就是说线程的同步出了错,从而会出现客户端无法收到信息的错误。还有一点要注意的是作为良好的编程习惯需要注意多个线程公用的变量要注意互斥操作,防止出现多线程中的“magic bugs”。同步与互斥,真是线程进程调度中的老大难啊,每次编程都要小心处理这两个问题,尽量避免不必要的错误。
Java Socket 多线程聊天室的更多相关文章
- java Socket多线程聊天程序
		
参考JAVA 通过 Socket 实现 TCP 编程 参考java Socket多线程聊天程序(适合初学者) 以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包 ...
 - [置顶]
        Chat Room:基于JAVA Socket的聊天室设计
		
d0304 更新功能实现 d0312 更新部分图片&UI设计部分 d0318 更新功能实现 d1222 实现添加好友功能.实现注册功能.修改大量BUG github:https://githu ...
 - 【C++】基于socket的多线程聊天室(控制台版)
		
以前学习socket网络编程和多线程编程的时候写的一个练手程序 聊天室基本功能: 1.用户管理:登录,注册,登出,修改用户名,修改密码 2.聊天室功能:群聊,私聊,获取在线用户列表,获取所有用户列表 ...
 - TCP多线程聊天室
		
TCP协议,一个服务器(ServerSocket)只服务于一个客户端(Socket),那么可以通过ServerSocket+Thread的方式,实现一个服务器服务于多个客户端. 多线程服务器实现原理— ...
 - Java实现简易聊天室
		
Java实现简易聊天室 在学习<Java从入门到精通>这本书,网络通信,基于TCP实现的简易聊天室,我这里对书中的代码略做了修改,做个记录. 这里先放一下运行效果图,代码放在最后. 运行效 ...
 - Socket.IO聊天室~简单实用
		
小编心语:大家过完圣诞准备迎元旦吧~小编在这里预祝大家元旦快乐!!这一次要分享的东西小编也不是很懂啊,总之小编把它拿出来是觉地比较稀奇,而且程序也没有那么难,是一个比较简单的程序,大家可以多多试试~ ...
 - java socket 多线程网络传输多个文件
		
http://blog.csdn.net/njchenyi/article/details/9072845 java socket 多线程网络传输多个文件 2013-06-10 21:26 3596人 ...
 - java基于socket公共聊天室的实现
		
项目:一个公共聊天室功能的实现,实现了登录聊天,保存聊天记录等功能. 一.实现代码 1.客户端 ChatClient.java import java.io.BufferedReader; impor ...
 - [Java小程序]聊天室——Socket和ServerSocket的使用
		
这段小代码是因为担任Java助教给刚学习Java的本科大二的小学弟小学妹们指导,他们的实验作业就是编写一个Java聊天室客户端和服务器,为了避免出纰漏,自己事先写了一下. 客户端Ui代码: packa ...
 
随机推荐
- composer(管理依赖关系的工具) 及配置信息
			
Composer 是 PHP 用来管理依赖(dependency)关系的工具.你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer 会帮你安装这些依赖的库文件. 配置文件 ...
 - php isset+{} 判断字符串长度比strlen效率高
			
PHP 变量后面加上一个大括号{},里面填上数字,就是指 PHP 变量相应序号的字符.例如:$str = 'hello';echo $str{0}; // 输出为 hecho $str{1}; // ...
 - Beautiful Soup (一)
			
一.Beautiful Soup库的理解 1.Beautiful Soup库可以说是对HTML进行解析.遍历.维护“标签树”的功能库 2.pip install bs4 3.from bs4 impo ...
 - Underscore.js 入门-常用方法介绍
			
Underscore.js是一个很精干的库,压缩后只有4KB.它提供了几十种函数式编程的方法,弥补了标准库的不足,大大方便了JavaScript的编程.MVC框架Backbone.js就将这个库作为自 ...
 - day46
			
CSS选择器 盒模型 标签a.img.list 伪类选择器 CSS选择器 一.基础选择器 1.通配选择器 - { border: solid; } 匹配文档中所有标签:通常指html.body及bod ...
 - 一个有趣的异步时序逻辑电路设计实例 ——MFM调制模块设计笔记
			
本文从本人的163博客搬迁至此. MFM是改进型频率调制的缩写,其本质是一种非归零码,是用于磁介质硬盘存储的一种调制方式.调制规则有两句话,即两个翻转条件: 1.为1的码元在每个码元的正中进行一次翻转 ...
 - kettle学习笔记(六)——kettle转换步骤
			
一.概述 转换步骤分类: 1. 增加新的列 2. 字符串处理 3. 行列变换 4. 排序/排重/字段选择 5. 其他转换步骤 二.增加新的列 1.增加常量列 增加一列常量的列 其它增加列的操作大同小异 ...
 - Python 语言简介
			
Python是一种计算机程序设计语言.你可能已经听说过很多种流行的编程语言,比如非常难学的C语言,非常流行的Java语言,适合初学者的Basic语言,适合网页编程的JavaScript语言等等. 那P ...
 - PHP  练习(租房子)
			
一.题目要求 二.题目做法 1.建立数据库 2.封装类文件 <?php class DBDA { public $fuwuqi="localhost"; //服务器地址 pu ...
 - CS50.2
			
1,ssd硬盘(solid state disk),固态硬盘,固盘. 2,把电磁信号转化为0或者1 ps:记得吧图给加上 反向即从磁盘中得到数据 3,软盘,floppy disk.早期使用的一种存储. ...