Java 网络聊天室 socket 极简版
两大类实现
涉及基本要素:
1. 多线程
2. 网络编程
3. TCP协议
4. 容器
效果图
分为客户端和服务器端
客户端 | 服务器端 |
---|---|
发送类封装 | 管道类封装 |
接收类封装 | 资源释放类 封装 |
资源释放类封装 |
客户端
package tcp;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("----MINI在线聊天室----");
Scanner scanner= new Scanner(System.in);
//BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入名字:");
String uname=scanner.nextLine();
//建立连接
Socket client=new Socket("localhost",8888);
new Thread(new ClientSend(client, uname)).start();
new Thread(new ClientReceive(client)).start();
}
//发送类 客户端的发送
static class ClientSend implements Runnable{
private BufferedReader cmd;
private DataOutputStream dos;
private Socket client;
private String uname;
private boolean go=false;
public ClientSend(Socket client,String uname)
{
this.client=client;
this.uname=uname;
cmd=new BufferedReader(new InputStreamReader(System.in));
this.go=true;
try {
dos=new DataOutputStream(client.getOutputStream());
//发送名字
send(uname);
} catch (IOException e) {
e.printStackTrace();
this.release();
}
} //构造器end
@Override
public void run()
{
while(go)
{
String msg;
try {
msg=cmd.readLine();//从控制台获取消息
if(!msg.equals(""))
{
send(msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//发送消息
private void send(String msg)
{
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
release();
}
}
//释放资源
private void release()
{
this.go=false;
Clean.close(dos,client);
}
}// ClientSend 类end
//接收类 客户端接收
static class ClientReceive implements Runnable{
private DataInputStream dis;
private Socket client;
private boolean go=false;
public ClientReceive(Socket client)
{
this.client=client;
this.go=true;
try {
this.dis=new DataInputStream(client.getInputStream());
} catch (IOException e) {
e.printStackTrace();
this.release();
}
}
//接收消息
private String receive()
{
String msg="";
try {
msg=dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
this.release();
}
return msg;
}
@Override
public void run() {
while(go)
{
String msg=this.receive();
if(!msg.equals(""))
{
System.out.println(msg);
}
}
}
//释放资源
private void release()
{
this.go=false;
Clean.close(this.dis,this.client);
}
}//ClientReceive 类end
//释放资源类封装
static class Clean {
public static void close(Closeable... targets) {
for(Closeable target:targets) {
try {
if(null!=target) {
target.close();
}
}catch(Exception e) {
e.printStackTrace();
}
}
}
}//clean类end
}
服务器端
package tcp;
import java.io.Closeable;
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 ChatServer {
private static CopyOnWriteArrayList<Channel>userArrayList=new CopyOnWriteArrayList<Channel>();
public static void main(String[] args) throws IOException {
ServerSocket server=new ServerSocket(8888);
System.out.println("----server-----");
while(true) {
Socket client=server.accept();
System.out.println("客户进行连接了");
Channel user=new Channel(client);
userArrayList.add(user);
new Thread(user).start();
}
}
static class Channel implements Runnable{
private DataInputStream dis;
private DataOutputStream dos;
private Socket client;
private boolean go;
private String uname;
public Channel(Socket client) {
this.client=client;
try {
dis=new DataInputStream(client.getInputStream());
dos=new DataOutputStream(client.getOutputStream());
this.go=true;
this.uname=receive();
this.send("欢迎加入");
this.sendOthers(uname+"加入聊天室",true);
} catch (IOException e) {
e.printStackTrace();
this.release();
}
}
//接受消息
private String receive() {
String msg="";
try {
msg=dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
this.release();
}
return msg;
}
//发送消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
this.release();
}
}
private void sendOthers(String msg,boolean System) {
boolean isPrivate=msg.startsWith("@");
if(isPrivate)
{
//私聊
//私聊格式@name:
int index=msg.indexOf(":");
String targetname=msg.substring(1,index);
msg=msg.substring(index+1);
for(Channel other:userArrayList)
{
if(other.uname.equals(targetname))
{
other.send(this.uname +"悄悄地对您说:"+msg);
break;
}
}
}else {
for(Channel other: userArrayList) {
if(other==this) { //自己
continue;
}
if(!System) {
other.send(this.uname +"对所有人说:"+msg);//群聊消息
}else {
other.send(msg); //系统消息
}
}
}
}
//释放资源
private void release() {
this.go=false;
Clean.close(dis,dos,client);
//删掉离开的人员
userArrayList.remove(this);
sendOthers(this.uname+"离开已离开聊天室...",true);
}
@Override
public void run() {
while (go) {
String msg=this.receive();
if(!msg.equals("")) {
sendOthers(msg, false);
}
}
}
}//Channel类 end
//释放资源类封装
static class Clean {
public static void close(Closeable... targets) {
for(Closeable target:targets) {
try {
if(null!=target) {
target.close();
}
}catch(Exception e) {
e.printStackTrace();
System.out.println("---clean------");
}
}
}
}//clean类end
}
客户端接收和发送类继承Runnable接口重写run()方法实现接收发送同时进行不阻塞。
服务端管道类类继承Runnable接口重写run()方法,每当有一个用户登录就产生一个连接管道并加入容器,实现并发交流。