解决方案 »
- 【新手学java】关于对象比较和内存分配存储方式讨论专贴
- 关于java关键字
- 帮忙修改一下一个小程序(偶自己不懂JAVA),谁帮我忘APPLET显示的计算器上多显示一行文本?
- 关于排序的问题
- 不知道该如何处理JOptionPane.showInputDialog对话框中的取消事件
- double类型四舍五入取两位小数,java中程序怎样写?
- 求解决方法~~数据库SQL SERVER自动增的问题~
- 简单问题!!为什么现在jdk1.4,1.5的安装程序那么大4,50M,以前的jdk1l.3才几M?谢谢
- 使窗体一开始窗体的大小为
- 对Jbulid 4.0 IDE熟的请进!!!
- setPreferredSize()方法,怎样理解?与setBounds()有什么区别?
- 自己写的一个快速排序算法,当数字为1500时,在MyEclipse下运行后显示不出结果!
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;public class Server implements Runnable{
ServerSocket ss = null;
Socket fatherS = null;
Socket shutdownSocket = null;
List<MyClient> clients = new ArrayList<MyClient>();
boolean keepConnect = false;
BufferedReader br = null;
MyClient mc = null;
String messageFromServer = null;
boolean isServerAvailable = true;
boolean allSocketClosed = false;
int count = 0;
public Server() {
this.startServer();
(new Thread(this)).start();
this.acceptSocket();
} public static void main(String[] args) {
new Server();
}
public void startServer() {
try {
this.ss = new ServerSocket(8888);
this.keepConnect = true;
} catch (IOException e) {
e.printStackTrace();
}
}
public void acceptSocket() {
while(keepConnect) {
try {
fatherS = ss.accept();
if(isServerAvailable) {
mc = new MyClient(fatherS);
mc.start();
clients.add(mc);
mc = null;
} else {
while(shutdownSocket == null) {
//空转,等到shutdownSocket真正被分配到以后再进行下一步操作
}
//结束阻塞的专用socket
System.out.println(shutdownSocket);
shutdownSocket.close();
fatherS.close();
System.out.println("shutdownSocket关闭了吗?" + shutdownSocket.isClosed());
//将 keepConnect 的值设置为 false,使跳出 acceptSocket() 阻塞方法!
keepConnect = false;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//起这个线程的目的就是为了能受控制地关闭服务器
public void run() {
br = new BufferedReader(new InputStreamReader(System.in));
do {
try {
messageFromServer = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
} while(!messageFromServer.equals("shutdown")); try {
isServerAvailable = false;
//构造一个虚假的 socket 连接到服务器自身,用于关闭服务器的 accept() 阻塞性方法!
shutdownSocket = new Socket("127.0.0.1", 8888);
} catch (Exception e) {
e.printStackTrace();
}
while(!((shutdownSocket.isClosed())&&(shutdownSocket.isConnected()==true))) {
//空转,当shutdownSocket连接成功过且关闭了以后,进入到下一步!
}
//解决了阻塞性方法和无限循环,进入下一步:
//向 clients 集合中的每一个客户端所对应的连接对象发送一条断开命令
for(int i = 0; i < clients.size(); i ++) {
try {
((MyClient)clients.get(i)).dos.writeUTF("shutdown");
} catch (IOException e) {
e.printStackTrace();
}
} //当clients中所有MyClient对象的socket被关闭之后,再跳出这个while循环进入到下一步!
while(!allSocketClosed) {
for(int i = 0; i < clients.size(); i ++) {
if(((MyClient)clients.get(i)).childS.isClosed()) {
count ++;
}
}
if(count == clients.size()) {
allSocketClosed = true;
} else {
//归0,要不count的值将会一直增长下去,服务器就永远别想关闭了!
count = 0;
}
}
//最后一步,关闭 ServerSocket 对象,大功告成!
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
class MyClient extends Thread {
Socket childS = null;
DataOutputStream dos = null;
DataInputStream dis = null;
String message = null;
boolean bConnected = false;
MyClient tempMc = null; public MyClient(Socket s) {
bConnected = true;
childS = s;
try {
this.dos = new DataOutputStream(this.childS.getOutputStream());
this.dis = new DataInputStream(this.childS.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while(bConnected) {
try {
message = dis.readUTF();
if(message.equals("disconnect")) {
//dis 和 dos 中关掉任意一个,socket连接都会自动关掉
dos.writeUTF("disconnect");
clients.remove(this);
dis.close();
System.out.println("一个客户端通过键入disconnect的方式温和地退出了!(可以放心,它已经退踢出列表了)");
bConnected = false;
} else if(message.equals("shutdown")) {
//我就是没想通@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//这个问题花费了我3四个小时!!
//问题的关键在于:从 clients 集合里移除某些 MyClient 对象了以后,
//clients 集合里面剩余的对象的次序会发生改变,集合的大小 size 也会发生改变
//这样就导致了一些客户端根本就没法收到从服务器端发过去的 shutdown 命令!
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//下面这行代码就是这个问题的罪魁祸首!
// clients.remove(this);
dis.close();
System.out.println("这场关闭狂潮由服务器发起!一个客户端已成功退出!");
bConnected = false;
} else {
//转发给所有的客户端!
for(int i = 0; i < clients.size(); i ++) {
tempMc = (MyClient)clients.get(i);
tempMc.dos.writeUTF(message);
}
//只返还给发信息过来的客户端!
// dos.writeUTF("这是服务器端返还给客户端的信息:" + message);
}
} catch (SocketException e) {
clients.remove(this);
try {
dis.close();
} catch(Exception ex) {
System.out.println("本来就出错了,在出错的错误处理中又出错了!");
}
//以下代码导致该线程终结
System.out.println("一个客户端没有提前跟 Server端 商量就粗暴地退出了!(可以放心,它已经退踢出列表了)");
bConnected = false;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;//写出个类源自改进别人写的Server1的想法
public class Client implements Runnable {
Socket s = null;
DataInputStream dis = null;
DataOutputStream dos = null;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
InputStreamReader isr = null;
boolean isConnected = false;
String message = null;
String keyin = null;
public static void main(String[] args) {
Client c = new Client();
c.connect();
(new Thread(c)).start();
c.receiveKeyin();
}
public void connect() {
try {
s = new Socket("127.0.0.1", 8888);
isConnected = true;
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
System.out.println("请先打开服务器!!");
}
}
public void receiveKeyin() {
while(isConnected) {
try {
keyin = br.readLine();
if(keyin.equals("disconnect")) {
dos.writeUTF("disconnect");
System.out.println("客户端自行正常关闭!");
//作用相当于break;
isConnected = false;
//暂时就不关了,等发至服务器的disconnect传回来被线程收到停止线程以后再关
// dos.close();
} else {
System.out.println(keyin);
dos.writeUTF(keyin);
}
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public void run() {
while(isConnected) {
try {
//在接收键盘输入 disconnect 以后,
//dos 的关闭导致整个socket连接的关闭
//此时主方法已经走到尽头,但是还有一个线程因为在执行 readUTF() 方法阻塞在那里
//socket 连接的关闭导致该线程抛出 SocketException !
message = dis.readUTF();
if(message.equals("disconnect")) {
//直接break,判断都省去了
//其实这里什么都不写也一样的,因为在上面 isConnected 的值已经被设为 false 了
//dis 关闭后 dos、s 都将关闭!
dis.close();
if(br != null) {
br.close();
}
break;
} else if(message.equals("shutdown")) {
//将 shutdown 回发给 Server 端
dos.writeUTF("shutdown");
dos.close();
System.out.println("客户端的socket连接是否已经被关闭:" + s.isClosed());
//一下这种方式不能关掉前面调用的 readLine() 阻塞性方法。
//相反,貌似还会阻塞住这支线程的正常终止(while循环后面那行输出迟迟没出现在控制台上)!!!
// br.close();
break;
} else {
System.out.println(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("客户端用于接收从服务器端发过来消息的线程已经被关闭了!");
}
}