客户端与服务端的Socket通信

xiaoxiao2021-02-28  85

客户端:

public class Client { /* * java.net.Socket * 套接字,封装了TCP协议,使用它可以与远端计算机通讯 */ private Socket socket; /* * 定义构造方法,用来初始化客户端 */ /* * 实例化Socket时需要传入两个参数: * 1:服务端计算机的地址信息(IP地址) * 2:服务端计算机上运行的服务端应用程序申请的服务端口 * * * 通过IP可以找到服务端的计算机,通过端口可以连接到运行在服务端计算机上的服务端应用程序 * * 实例化Socket的过程就是连接服务端的过程,若服务端无响应,实例化过程会抛出异常 * * 端口号是一个整数,2字节内的整数0-65536 * 但3000以内的端口号不要使用,因为紧密的绑定着系统程序,和世界上流行的应用程序。 * 10000以上也很少被使用 */ public Client() throws Exception{ try { Scanner scanner=new Scanner(System.in); String str=scanner.nextLine(); socket=new Socket(str,8088);//"176.195.107.86" System.out.println(str); System.out.println("连接上服务端!"); } catch (Exception e) { //记录日志 throw e; } } public void start(){ try{ //用来获取用户输入 Scanner scanner=new Scanner(System.in); /** * Socket提供方法: * OutputStream getOutputStream() * 通过获取的输出流写出的数据就可以通过 * 网络发送给远端计算机,对于客户端而言远端就是服务器。 */ OutputStream out=socket.getOutputStream(); //String message="你好服务端"; //byte[] data=message.getBytes("UTF-8"); OutputStreamWriter osw=new OutputStreamWriter(out,"UTF-8"); PrintWriter pw=new PrintWriter(osw,true); //接收客户端发送过来的消息的线程启动 ServerHandler handler=new ServerHandler(); Thread t=new Thread(handler); t.start(); System.out.println("请开始聊天吧!"); String message=null; long time=System.currentTimeMillis()-500; while(true){ message=scanner.nextLine(); if(System.currentTimeMillis()-time>=500){ pw.println(message); time=System.currentTimeMillis(); }else{ System.out.println("你说话过快!"); time=System.currentTimeMillis(); } } //pw.close(); }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] args) {//程序入口方法,没有逻辑代码 Client client; try { client = new Client(); client.start(); } catch (Exception e) { e.printStackTrace(); System.out.println("服务端启动失败"); } } /** * 该线程专门用来循环读取服务端发送过来的消息并输出 * 到客户端的控制台上 * @author live * */ private class ServerHandler implements Runnable{ public void run() { try{ InputStream in=socket.getInputStream(); InputStreamReader isr =new InputStreamReader(in,"UTF-8"); BufferedReader br =new BufferedReader(isr); String message=null; while((message=br.readLine())!=null){ System.out.println(message); } }catch(Exception e){ } } } } 服务端:

public class Server { /** * 运行在服务端的ServerSocket主要负责两个工作: * 1:向系统申请服务端口,客户端就是通过这个端口与服务端应用程序建立连接的。 * 2:监听服务端口,一旦客户端通过该端口尝试连接时,ServerSocket就会实 * 例化一个Socket与该客户端通讯。 */ private ServerSocket server; //存放所有客户端的输出流,用于广播消息 private List<PrintWriter> allOut; public Server() throws Exception{ try{ /** * 实例化SeverSocket时需要指定服务端口,客户端就是通过这个端口与服务端建立连接的。 * * 该端口不能与系统其他程序申请的端口冲突,否则会抛出异常。 * address already in use */ server=new ServerSocket(8088); allOut=new ArrayList<PrintWriter>(); }catch(Exception e){ throw e; } } public void start(){ try{ /* * ServerSocket提供方法: * Socket accept() * 该方法是一个阻塞方法,调用后会一致等待客户端的连接,一旦一个客户端 * 通过ServerSocket申请的端口建立连接,那么accept方法会返回一个 * Socket实例,通过该Socket实例可以与建立连接的客户端进行通讯 */ while(true){ System.out.println("等待客户端连接。。。。。。。。。"); Socket socket=server.accept(); System.out.println("一个客户端连接了"); //启动一个线程来处理该客户端交互 ClientHandler handler= new ClientHandler(socket); Thread t=new Thread(handler); t.start(); } }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] args) { try{ Server server=new Server(); server.start(); }catch(Exception e){ e.printStackTrace(); System.out.println("服务端启动失败"); } } /* * 该线程任务是用于处理与指定客户端的交互工作。 */ private class ClientHandler implements Runnable{ //当前线程通过这个Socket与指定客户端交互 private Socket socket; //该客户端的地址信息 private String host; public ClientHandler(Socket socket){ this.socket=socket; //通过Socket获取远端计算机地址信息 InetAddress address=socket.getInetAddress(); //获取IP地址的字符串形式 host=address.getHostAddress(); } public void run() { PrintWriter pw = null; try{ /* * Socket提供方法: * InputStream getInputStream() * 通过获取的输入流读取的字节就是来自远端发送过来的数据,对于服务端而言, * 远端指的就是客户端。 */ InputStream in=socket.getInputStream(); InputStreamReader isr=new InputStreamReader(in,"UTF-8"); BufferedReader br=new BufferedReader(isr); /* * 通过Socket获取输出流,用于将消息发送给客户端 */ OutputStream out=socket.getOutputStream(); OutputStreamWriter osw=new OutputStreamWriter(out,"UTF-8"); pw=new PrintWriter(osw,true); //将该客户端的输出流存入共享集合 synchronized (allOut) {//给allOut加锁,保证线程安全 allOut.add(pw); } String message=null; /* * 使用br.readline读取客户端发送过来的一行字符串时,该方法处于阻塞状态 * 直到客户端真实发送过来一行,这里才会返回 * * 但是当客户端断开连接时,br.readline会根据客户端不同操作系统有不同的反馈 * 当Windows的客户端断开,br.readline方法会抛出异常 * 当Linux的客户端断开,br.readline方法会返回null. */ while((message=br.readLine())!=null){ //System.out.println(host+"说:"+message); /*//将读到的内容再回复给客户端(临时测试用) pw.println("回复:"+message); */ /* * 将消息转发给所有客户端 */ synchronized (allOut) { for(PrintWriter o:allOut){ o.println(host+"说:"+message+"\n连接人数:"+allOut.size()); } } } }catch(Exception e){ } finally { /* * 当客户端断线,要将输出流从共享集合中删除 * 需要同步 * * 处理客户端断开连接的操作 */ synchronized (allOut) { allOut.remove(pw); } try{ socket.close(); }catch(IOException e){ e.printStackTrace(); } } } } }

转载请注明原文地址: https://www.6miu.com/read-21196.html

最新回复(0)