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 ...
随机推荐
- 【转】ios tableView那些事(一)创建一个简单的tableView
工作也有半年多了!几乎每个项目中的会用到tableview这个神奇而好用的控件,在学习和工作中都会看别人的博客!对我有很大的帮助,就如同站在巨人的肩膀上的感觉吧 哈哈!于是决定重新开始写博客,希望能帮 ...
- kubernetes label 标签使用
查看node的标签kubectl get node --show-labels 删除标签kubectl label nodes node5 storagenode- 设置标签kubectl label ...
- Git系列七之备份迁移 升级 恢复管理
0.Gitlab安装 1.安装和配置必要的依赖关系在CentOS7,下面的命令将在系统防火墙打开HTTP和SSH访问. yum install curl openssh-server postfix ...
- 智能家居 (2)手机一键自配置APP
说明 本教程主要记录APP端一键自配置功能+TCP/IP通信 0配套使用单片机烧录 /* 文件名称:smartconfig.ino 功能:ESP8266快速配置功能 作者:www.doit.am 日期 ...
- 爬虫代理squid
yum -y install squid 配置文件一般是在/etc/squid3/下的squid.conf文件 pyspider使用的时候只需要设置代理服务器为你配置好的服务器的IP就可以了 clas ...
- DQN(Deep Reiforcement Learning) 发展历程(三)
目录 不基于模型(Model-free)的预测 蒙特卡罗方法 时序差分方法 多步的时序差分方法 参考 DQN发展历程(一) DQN发展历程(二) DQN发展历程(三) DQN发展历程(四) DQN发展 ...
- day 26
今日内容 classmethod 让这个类中的方法绑定自己类,这样就可以直接用类调用该方法. staticmethod 让类中的方法编程非绑定方法,也就是是这个类中的方法编程普通函数. ####### ...
- 网络对抗技术 2017-2018-2 20152515 Exp 8 Web基础
1.本实践的具体内容: (1).Web前端HTML(0.5分) 输入命令apachectl start打开apahce,并查看端口号,确认apache开启: 在kali浏览器中输入localhost: ...
- 20155310 《网络攻防》Exp4 恶意代码分析
20155310 <网络攻防>Exp4 恶意代码分析 基础问题 1.如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些, ...
- 预定义的类型“System.Object”未定义或未导入
打开一个以前的程序 ,发现报这个错误.检查了程序,发现程序的引用 System 不见了 ,尝试 引用失败.. 查了有人说重新建立 Sln文件有用.. 一头雾水,随后 尝试操作 ,程序有用了 具体步骤: ...