本案例模拟聊天室,有着群发和私聊的功能,一切都在console中进行,没有界面,采用oop思想,封装操作
代码如下:
服务器端:服务端需要连接多个客户端,因此需要循环监听,每次连接一个客户端创建一个Channel线程,然后再次阻塞式监听。
package com.chatroot.java;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;
public class Chat {
private static CopyOnWriteArrayList
private static int count = 0;
public static void main(String[] args) throws IOException {
System.out.println("-----服务器端-----");
ServerSocket server = new ServerSocket(9999);
while(true) {
Socket client = server.accept();
Channel c = new Channel(client);
list.add(c);
count++;//记录连接客户端的数目
System.out.println("一个客户端建立连接");
System.out.println("当前客户端数目为:"+count);
new Thread(c).start();
}
}
static class Channel implements Runnable{
private DataInputStream dis = null;
private DataOutputStream dos = null;
private Socket client;
private String name;
private boolean isRunning;
public Channel(Socket client) {
this.client = client;
try {
isRunning = true;
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
this.name = receive();
send("欢迎进入天地聊天室");
sendOther("欢迎"+this.name+"的加入",true);
} catch (IOException e) {
release();
}
}
//接受消息
private String receive() {
String msg = "";//避免空指针
try {
msg = dis.readUTF();
} catch (IOException e) {
release();
}
return msg;
}
//发送消息
private void sendOther(String msg,boolean isSys) {
boolean isPrivate = msg.startsWith("@");
if(isPrivate) {
int index = msg.indexOf(":");
String target = msg.substring(1, index);
String data = msg.substring(index+1);
for(Channel other:list) {
if(other.name.equals(target)) {
other.send(this.name+"悄悄的对您说"+data);
break;
}
}
}else {
for(Channel other:list) {
if(other==this) {
continue;
}
if(isSys) {
other.send(msg);
}else {
other.send(this.name+"说:"+msg);
}
}
}
}
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//释放资源
private void release() {
isRunning = false;
CloseUnits.close(dis,dos,client);
list.remove(this);
sendOther(this.name+"退出天地聊天室", true);
count--;
System.out.println("当前客户端数:"+count);
}
@Override
public void run() {
while(isRunning) {
String msg = receive();
if(!msg.equals("")) {
sendOther(msg,false);
}
}
}
}
}
客户端:客户端需要实现读和写独立进行,因此需要多线程,一个线程读,一个线程写,各不干涉。
package com.chatroot.java;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("----客户端----");
System.out.print("请输入用户名:");
String name = br.readLine();
Socket client = null;
try {
client = new Socket("localhost",9999);
}
catch (Exception e) {
System.out.println("服务器已经关闭");
}
new Thread(new Send(client,name)).start();
new Thread(new Receive(client)).start();
}
}
分别封装读发送和接受操作
发送端:
package com.chatroot.java;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class Send implements Runnable{
private DataOutputStream dos;
private BufferedReader br;
private String msg;
private String name;
private Socket client;
public Send(Socket client,String name) {
try {
this.client = client;
this.name = name;
dos = new DataOutputStream(client.getOutputStream());
br = new BufferedReader(new InputStreamReader(System.in));
send(name);
} catch (IOException e) {
release();
}
}
@Override
public void run() {
boolean isRunning = true;
while(isRunning) {
msg = getStrFromConsole();
if(!msg.equals("")) {
send(msg);
}
}
}
public String getStrFromConsole() {
String msg = "";
try {
msg = br.readLine();
} catch (IOException e) {
return "";
}
return msg;
}
public void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
release();
}
}
public void release() {
CloseUnits.close(br,dos,client);
System.out.println("服务器已经关闭");
}
}
接受:
package com.chatroot.java;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
public class Receive implements Runnable{
private DataInputStream dis;
private String msg;
private Socket client;
public Receive(Socket client) {
try {
this.client = client;
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
release();
}
}
@Override
public void run() {
boolean isRunning = true;
while(isRunning) {
try {
msg = dis.readUTF();
System.out.println(msg);
} catch (IOException e) {
isRunning = false;
release();
}
}
}
public void release() {
CloseUnits.close(dis,client);
}
}
将流和资源释放独立封装
package com.chatroot.java;
import java.io.Closeable;
import java.io.IOException;
public class CloseUnits {
public static void close(Closeable...closeables) {
for(Closeable target:closeables) {
try {
target.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}