JAVA代码实现利用多进程实现C/S模式聊天程序,启动一个服务器,单个和多个客户端,服务端接收到新的客户端 请求就创建一个进程与客户端通信,同时实现不同客户端之间的消息交流

本文介绍了Java中使用Socket进行网络通信的基本步骤,包括客户端与服务器的交互流程,并展示了多线程在客户端和服务端的应用。客户端通过Socket连接服务器,发送和接收消息,服务端则监听客户端连接,接收并回应消息。代码示例展示了如何创建线程来处理输入输出流,以及在客户端和服务端实现多线程通信。
摘要由CSDN通过智能技术生成

一:想要看懂该java代码,需要掌握以下知识点

环境:eclipse,idea

  1. 进程的创建和启动
                @Override
                public void run() {
                    //这里放你的想要线程执行的代码
                }
            };
           new Thread(){}.start();//调用start()方法,启动线程,执行run()方法的代码          ```
    
  2. 输入输出流 不做过多介绍!
  3. socket网络通信
    客户端Socket的工作过程包含以下四个基本的步骤
       1.创建 Socket:根据指定服务端的IP地址或端口号构造 Socket 类对象。若服务器端 响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
       2.打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用
    getOutputStream()方法获得输出流,进行数据传输
       3.按照一定的协议对 Socket进行读/写操作:通过输入流读取服务器放入线路的信息 (但不能读取自己放入线路的信息),通过输出流将信息写入线程。
       4.关闭 Socket:断开客户端到服务器的连接,释放线路
Socket s = new 
Socket(192.168.40.165,9999);//表示服务端所在的电脑的IP为(192.168.40.165),端口号大于1000,基本没事,端口号为9999
OutputStream out = s.getOutputStream();
out.write(" hello".getBytes());
s.close();

注:
 1.该代码的客户端和服务端可以在不同的电脑执行,可以多台电脑运行同一份客户端代码
 2.获取本机IP的方式:

import org.junit.Test;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class test {
    @Test
    public void test() throws UnknownHostException {
        System.out.println(InetAddress.getLocalHost());
    }
}
//结果:admin/169.254.239.139

服务器程序的工作过程包含以下四个基本的步骤:
   1.调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。
   2.调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
   3.调用 该Socket类对象的getOutputStream() 和getInputStream ():获取输出流和输入流,开始网络数据的发送和接收。
   4.关闭ServerSocket和Socket对象:客户端访问结束.关闭通信套接字。
注:
 1.ServerSocket 对象负责等待客户端请求建立套接字连接,类似邮局某个窗口 中的业务员。也就是说,服务器必须事先建立一个等待客户请求建立套接字 连接的ServerSocket对象。
 2.所谓“接收”客户的套接字请求,就是accept()方法会返回一个 Socket 对象

ServerSocket ss = new ServerSocket(9999); //端口号对应,才能正确接收客户端的请求
Socket s = ss.accept ();
InputStream in = s.getInputStream();
 byte[] buf = new byte[1024];
int num = in.read(buf);
String str = new String(buf,0,num);
System.out.println(s.getInetAddress().toString()+:+str);
 s.close();
ss.close();

4.其余的一些java的基本语法

二:废话不多少,直接上代码!

客户端

package socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

/**
 * Created by HeTingwei on 2017/12/9.
 * 多线程客户端
 */
public class Client1 {
   private Socket socket;
    private static final int MESSAGE_SIZE = 1024;//每次允许接受数据的最大长度

    public static void main(String[] args) {//169.254.239.139
    	Scanner in=new Scanner(System.in);
    	System.out.println("是否要连接服务武器Y or N?");
    	String s = in.next();
    	if(s.equals("Y")) {
    		Client1 client = new Client1();
    		
    		 new Thread() {//开启一个接受数据的线程
                 @Override
                 public void run() {
                     super.run();
                     InputStream in;
                     try {
                         in = client.getSocket().getInputStream();
                         byte[] b;
                         while (true) {
                             b = new byte[MESSAGE_SIZE];
                             in.read(b);
                             System.out.println("接收到服务端消息:" + new String(b));
                         }
                     } catch (IOException e) {
                         e.printStackTrace();
                     }
                 }
             }.start();
             
    		 OutputStream out = null;
             while (true) {     //循环发消息,遇到end结束    
                 String str = in.nextLine();
                 //异常处理
                 try {
					out = client.getSocket().getOutputStream();//向客户端发送
					out.write(str.getBytes());
					out.flush();
                 if (str.equals("end")) {
                     System.exit(0);//关闭客户端
                 }
				} catch (IOException e) {
					e.printStackTrace();
				}
             }
          
    	}else {
			System.out.println("服务终止");
		}
           in.close();
    }

    public Client1() {//构造器
        try {
            socket = new Socket("169.254.239.139", 45678);
            if (socket.isConnected() == true) {
                System.out.println("连接成功");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

	public Socket getSocket() {
		return socket;
	}
    
}

服务端
服务端进程包括两个线程类:接受服务端的消息的线程,给服务端发消息的线程
还有一个List集合,存放已连接客户端类

package socket;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by HeTingwei on 2017/12/9.
 * 多线程服务器,实现多客户端聊天
 */
public class Server {

    List<ReceiveThread> receiveList = new ArrayList<>();//存放已连接客户端类
    private final static int MESSAGE_SIZE = 1024;//每次允许接受数据的最大长度
    int num = 0;//客户端编号

    public static void main(String[] args) {
        new Server();
    }

    //服务端处理逻辑
    Server() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(45678);//用来监听的套接字,指定端口号
            while (true) {
                Socket socket = serverSocket.accept();//监听客户端连接,阻塞线程
                System.out.println("连接上客户端:" + num);
                									//在其他线程处理接收来自客户端的消息
                ReceiveThread receiveThread = new ReceiveThread(socket, num);
                receiveThread.start();
                receiveList.add(receiveThread);

                //有客户端新上线,服务器就通知其他客户端
                String notice="有新客户端上线,现在在线客户端有:客户端:";
                for (ReceiveThread thread : receiveList) {
                    notice = notice + " " + thread.num;
                }
                for (ReceiveThread thread : receiveList) {
                    new SendThread(thread.socket, notice).start();
                }
                num++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    //接受消息的线程(同时也有记录对应客户端socket的作用)
    class ReceiveThread extends Thread {
        int num;
        Socket socket;//客户端对应的套接字
        boolean continueReceive = true;//标识是否还维持连接需要接收

        public ReceiveThread(Socket socket, int num) {
            this.socket = socket;
            this.num = num;
            try {
                //给连接上的客户端发送,分配的客户端编号的通知
                socket.getOutputStream().write(("你的客户端编号是" + num).getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            super.run();
            //接收客户端发送的消息
            InputStream inputStream = null;
            try {
                inputStream = socket.getInputStream();
                byte[] b;
                while (continueReceive) {
                    b = new byte[MESSAGE_SIZE];
                    inputStream.read(b);
                    b = splitByte(b);//去掉数组无用部分
                    //发送end的客户端断开连接
                    if (new String(b).equals("end")) {
                        continueReceive = false;
                        receiveList.remove(this);
                        //通知其他客户端
                        String message = "客户端" + num + "连接断开\n" +"现在在线的有,客户端:";
                                
                        for (ReceiveThread receiveThread : receiveList) {
                            message = message + " " + receiveThread.num;
                        }
                        System.out.println(message);
                        for (ReceiveThread receiveThread : receiveList) {
                            new SendThread(receiveThread.socket, message).start();
                        }
                    } else {
                        try {
                            String[] data = new String(b).split(" ", 2);//以第一个空格,将字符串分成两个部分
                            int clientNum = Integer.parseInt(data[0]);//转换为数字,即客户端编号数字
                            //将消息发送给指定客户端
                            for (ReceiveThread receiveThread : receiveList) {
                                if (receiveThread.num == clientNum) {
                                    new SendThread(receiveThread.socket, "客户端"+num+"发消息:"+data[1]).start();
                                    System.out.println("客户端" + num + "发送消息到客户端" + receiveThread.num + ": " + data[1]);
                                }
                            }
                        } catch (Exception e) {
                            new SendThread(socket, "输入错误,请重新输入").start();
                            System.out.println("客户端输入错误");
                        }

                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {//关闭资源
                    if (inputStream != null) {
                        inputStream.close();
                    }
                    if (socket != null) {
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //发送消息的线程
    class SendThread extends Thread {
        Socket socket;
        String str;

        public SendThread(Socket socket, String str) {
            this.socket = socket;
            this.str = str;
        }

        @Override
        public void run() {
            super.run();
            try {
                socket.getOutputStream().write(str.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
    //去除byte数组多余部分
   private   byte[] splitByte(byte b[]) {
        int i = 0;
        for(;i<b.length;i++) {
            if (b[i] == 0) {
                break;
            }
        }
        byte[] b2 = new byte[i];
        for (int j = 0; j <i ; j++) {
            b2[j] = b[j];
        }
        return b2;
    }

}


三运行示例:

发消息示例:你要向哪个客户端发消息<空格>消息
在这里插入图片描述
在这里插入图片描述

其余的不懂得可以在评论区探讨

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值