网络编程(六)聊天室代码实现

先写一个客户端输入数据,服务器端处理数据后返回给客户端

客户端:

public static void main(String[] args) throws UnknownHostException, IOException {

Scanner sc = new Scanner(System.in);
System.out.println("请客户端输入:");
String msg = sc.nextLine();

//创建客户端 指定服务器及端口 此时就在连接
Socket client = new Socket("localhost",9999);

//客户端输出数据 输出流
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF(msg);
dos.flush();

//客户端读取数据, 输入流
DataInputStream dis = new DataInputStream(client.getInputStream());
msg = dis.readUTF();
System.out.println(msg);

}

服务器端:

public static void main(String[] args) throws IOException {
//创建服务器,指定端口
ServerSocket server = new ServerSocket(9999);
//接收客户端连接 阻塞式 该socket和客户端的socket是同一个socket
Socket socket = server.accept();

//服务器端读取数据, 输入流
DataInputStream dis = new DataInputStream(socket.getInputStream());
String msg = dis.readUTF();

//服务器端输出数据 输出流
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(msg + " 服务器端输出");
dos.flush();

}

启动服务器端后启动客户端:

请客户端输入:
你好

你好 服务器端输出


上述代码存在的问题,处理完一条数据就结束了,要想实现一直保持通信,加入死循环。输入流和输出流在同一个线程内 应该独立处理 彼此独立 引入多线程

服务器端:

public class ThreadServer {

public static void main(String[] args) throws IOException {

//创建服务器,指定端口
ServerSocket server = new ServerSocket(9999);
//接收客户端连接 阻塞式 该socket和客户端的socket是同一个socket
Socket socket = server.accept();
DataInputStream dis = new DataInputStream(socket.getInputStream());
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

while(true){
//服务器端读取数据, 输入流
String msg = dis.readUTF();
//服务器端输出数据 输出流
dos.writeUTF(msg + " 服务器端输出");
dos.flush();
}
}

}

客户端:

public class ThreadClient {

public static void main(String[] args) throws UnknownHostException, IOException {

//创建客户端 指定服务器及端口 此时就在连接
Socket client = new Socket("localhost",9999);
new Thread(new Send(client)).start(); //一条路径
new Thread(new Receive(client)).start();//另一条路径
}
}

发送数据封装类:

public class Send implements Runnable{

//输入数据 控制台
private BufferedReader console; 
//输出流
private DataOutputStream dos;
//是否running
private boolean isRunning = true;

public Send(Socket client){
console = new BufferedReader(new InputStreamReader(System.in));
try {
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
isRunning = false;
CloseUtil.closeAll(console,dos);
}
}

//控制台接收数据
public String getMsgFromClient(){
try {
return console.readLine();
} catch (IOException e) {

}
return "";
}

//发送信息
public void send(){
String msg = getMsgFromClient();
try {
if(null != msg && !msg.equals("")){
dos.writeUTF(msg);
dos.flush();
}
} catch (IOException e) {
isRunning = false;
CloseUtil.closeAll(console,dos);
}
}

@Override
public void run() {


while(isRunning){
send();
}
}
}

接收数据封装类:

public class Receive implements Runnable{


//输入流 读取数据
private DataInputStream dis;
//是否running
private boolean isRunning = true;

public Receive(Socket client){
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
isRunning = false;
CloseUtil.closeAll(dis);
}
}

//接收信息
public String receive() {
String msg = "";
try {
msg = dis.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
isRunning = false;
CloseUtil.closeAll(dis);
}
return msg;
}

@Override
public void run() {
while(isRunning){
System.out.println(receive());
}
}
}

关闭流工具类:

public class CloseUtil {

public static void closeAll(Closeable... io){

for(Closeable temp : io){
try {
if(null != temp){
temp.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

上述代码中只实现了一个客户端,自己发送的数据自己接收,想当与自己给自己发送数据


群发:

给所有客户端发送数据

在上述代码的基础上只需要修改服务器端的代码

public class ThreadServer {


private List<MyChannel> list = new ArrayList<MyChannel>();

public static void main(String[] args) throws IOException {

new ThreadServer().start();
}


public void start() throws IOException{
//创建服务器,指定端口
ServerSocket server = new ServerSocket(9999);
//接收客户端连接 阻塞式 该socket和客户端的socket是同一个socket
while(true){
Socket client = server.accept();
MyChannel channel = new MyChannel(client);
list.add(channel);
new Thread(channel).start();
}


/**
 * 一个客户端 一条道路
 */
private class MyChannel implements Runnable{

private DataInputStream dis = null;
private DataOutputStream dos = null;
private boolean isRunning = true;

public MyChannel(Socket client){
try {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
isRunning = false;
CloseUtil.closeAll(dis,dos);
list.remove(this);
}
}

/**
* 获取数据
* @return
*/
private String receive(){

String msg = "";
try {
msg = dis.readUTF();
} catch (IOException e) {
isRunning = false;
CloseUtil.closeAll(dis);
list.remove(this);
}
return msg;
}

/**
* 发送数据
* @param msg
*/
private void send(String msg){
try {
if(null == msg || msg.equals("")){
return;
}
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
isRunning = false;
CloseUtil.closeAll(dos);
list.remove(this);
}
}

/**
* 发送给其他客户端
*/
private void sendOthers(){

String msg = this.receive();
for(MyChannel other : list){
if(other == this){
continue;
}
//发送给其他客户端
other.send(msg);
}
}

@Override
public void run() {


while(isRunning){
sendOthers();
}
}
}
}

启动服务器端 然后启动多个客户端(多次run as  ThreadClient)发现,后面启动的客户端,发送的数据前面启动的客户端都会接收到


此处我启动了三个客户端

第一次启动的客户端 


第二次启动


第三次启动 


回头看第一次启动的界面 发现接受到了第二次和第三次的数据


回头看第二次启动的界面 发现接受到第三次的数据



自学笔记,多有不足!!!


猜你喜欢

转载自blog.csdn.net/Kermit_father/article/details/80718997