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 ...
随机推荐
- swift static与class修饰符:static不参与动态派发
static与class 都有类型成员的含义:相对于实例成员: static的另一个意思是静态派发:所以不能被继承. 要使用动态派发和继承的机制必须使用class继承. static的其它常见含义: ...
- pyspider中内容选择器常用方法汇总
pyspider 的内容选择器默认已经实例化一个pyquery对象,可以直接使用pyquery的api来获取自己需要的内容. 1.在pyquery中使用response.doc就可以直接实例化一个py ...
- [浅谈CSS核心概念] CSS布局模型:float和position
1.流动模型 HTML元素在默认情况下都是按照"流动模型"进行布局的,网上也有人称之为"普通流"."文档流"之类的.这种布局模式的特点在于: ...
- php中addslashes(),htmlspecialchars()
参考转自http://czf2008700.blog.163.com/blog/static/2397283200937103250194/ addslashes -- 使用反斜线引用字符串 stri ...
- POJ 1328&&2109&&2586
这次是贪心(水笔贪心)专题. 先看1328,一道经典的导弹拦截(或者是打击?不懂背景). 大意是说在一个坐标系中有一些点(或是导弹),你要在x轴上建一些东西,它们可以拦截半径为d的圆范围中的点.问最少 ...
- maven mvn package 打包项目时,出现错误导致失败的解决方法
解决思路:看报错时在maven打包过程中的哪一步,然后看报错内容,解决报错内容即可,如果是实在不好解决的部分,看看能不能设置不检测,能打包出来就行. 这里是因为mybatis逆向工程插件出现异常所以中 ...
- Redis简介、安装、配置、启用学习笔记
前一篇文章有介绍关系型数据库和非关系型数据库的差异,现在就来学习一下用的较广的非关系型数据库:Redis数据库 Redis 简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-v ...
- CSS快速入门-基本选择器
1.标签选择器 通过标签进行元素选择. <style> a { font-size:10px; color:red; } </style> 2.* *代表通配符,匹配任意标签, ...
- wkhtmltopdf 参数介绍
wkhtmltopdf [OPTIONS]... <input file> [More input files] <output file> 常规选项 --allow &l ...
- CSS技巧收集——巧用滤镜
最近暴雪一款叫<守望先锋>的游戏火到不行,身边很多人都深受其毒害,虽然博主自己没有买(穷),但是耳濡目染也了解了个大概. 由于之前大致学习了一下 css 滤镜的各种用法,所以心血来潮结合二 ...