本来这次作业我是想搞个图形界面的,然而现实情况是我把题意理解错了,于是乎失去了最初的兴致,还是把程序变成了功能正确但是“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 多线程聊天室的更多相关文章

  1. java Socket多线程聊天程序

    参考JAVA 通过 Socket 实现 TCP 编程 参考java Socket多线程聊天程序(适合初学者) 以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包 ...

  2. [置顶] Chat Room:基于JAVA Socket的聊天室设计

    d0304 更新功能实现 d0312 更新部分图片&UI设计部分 d0318 更新功能实现 d1222 实现添加好友功能.实现注册功能.修改大量BUG github:https://githu ...

  3. 【C++】基于socket的多线程聊天室(控制台版)

    以前学习socket网络编程和多线程编程的时候写的一个练手程序 聊天室基本功能: 1.用户管理:登录,注册,登出,修改用户名,修改密码 2.聊天室功能:群聊,私聊,获取在线用户列表,获取所有用户列表 ...

  4. TCP多线程聊天室

    TCP协议,一个服务器(ServerSocket)只服务于一个客户端(Socket),那么可以通过ServerSocket+Thread的方式,实现一个服务器服务于多个客户端. 多线程服务器实现原理— ...

  5. Java实现简易聊天室

    Java实现简易聊天室 在学习<Java从入门到精通>这本书,网络通信,基于TCP实现的简易聊天室,我这里对书中的代码略做了修改,做个记录. 这里先放一下运行效果图,代码放在最后. 运行效 ...

  6. Socket.IO聊天室~简单实用

    小编心语:大家过完圣诞准备迎元旦吧~小编在这里预祝大家元旦快乐!!这一次要分享的东西小编也不是很懂啊,总之小编把它拿出来是觉地比较稀奇,而且程序也没有那么难,是一个比较简单的程序,大家可以多多试试~ ...

  7. java socket 多线程网络传输多个文件

    http://blog.csdn.net/njchenyi/article/details/9072845 java socket 多线程网络传输多个文件 2013-06-10 21:26 3596人 ...

  8. java基于socket公共聊天室的实现

    项目:一个公共聊天室功能的实现,实现了登录聊天,保存聊天记录等功能. 一.实现代码 1.客户端 ChatClient.java import java.io.BufferedReader; impor ...

  9. [Java小程序]聊天室——Socket和ServerSocket的使用

    这段小代码是因为担任Java助教给刚学习Java的本科大二的小学弟小学妹们指导,他们的实验作业就是编写一个Java聊天室客户端和服务器,为了避免出纰漏,自己事先写了一下. 客户端Ui代码: packa ...

随机推荐

  1. vue2.0路由切换后页面滚动位置不变BUG

    最近项目中遇到这样一个问题,vue切换路由,页面到顶端的滚动距离仍会保持不变.  方法一: 监听路由 // app.vue export default { watch:{ '$route':func ...

  2. AddHandler php5-script .php\AddType text/html .php和AddType application/x-httpd-php .php的区别?

    让apache支持php文件的解释,有2种方法配置,RPM装的默认配置是:AddHandler php5-script .phpAddType text/html .php网上很多人的配置方法是:Ad ...

  3. 编写简易的JS输入框模糊查询匹配(附有源码和demo)

    前言:JS输入框模糊匹配插件以前在工作写过一个类似的 所以这次写轻松很多,这次写优化了几个方面: 1. 添加动态加载css文件 不需要引入css css全部在JS动态生成. 2. 不需要额外的标签 只 ...

  4. DB2 substr,instr使用

    看示例,查询下一年'2xxx',例如今年2014,结果为2015 select substr(char(current timestamp),1,4)+1 from SYSIBM.SYSDUMMY1; ...

  5. Drupal错误:drupal Maximum execution time of 30 seconds exceeded database in解决方法

    Drupal开源内容管理框架 Drupal是使用PHP语言编写的开源内容管理框架(CMF),它由内容管理系统(CMS)和PHP开发框架(Framework)共同构成.连续多年荣获全球最佳CMS大奖,是 ...

  6. #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)

    ((GPIO_TypeDef *) GPIOA_BASE)表示将GPIOA_BASE强制转换为指针类型的结构体, #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) ...

  7. DOTNET Core 命令

    dotnet 命令目录: 1.dotnet-new 2.dotnet-restore 3.dotnet-build 4.dotnet-run 5.dotnet-test 6.dotnet-pack 7 ...

  8. SAP函数 LAST_DAY_OF_MONTHS 获取月末最后一天日期

    DATA LAST_DATE TYPE SY-DATUM. CALL FUNCTION 'LAST_DAY_OF_MONTHS' EXPORTING day_in = sy-datum IMPORTI ...

  9. 网络对抗技术 2017-2018-2 20152515 Exp1 PC平台逆向破解 笔记

    Exp1 PC平台逆向破解 1.堆栈不可保护: ROP 2.alsr 随机化: 填充NOPS "\90" 3.不加堆栈保护 shellcode: 1.不依赖外部函数 2.不含\00 ...

  10. POJ3278&&1426&&3126&&3087&&3414

    接上次的,标签是BFS专题 其实无论是Deepth还是Breadth都是Search 3278 又是撸过的题目 1426 找一个十进制数(我刚开始看样例以为是二进制数),使得它每一位上都是1或0,且是 ...