Java实现本地Socket通信(三)

📅 2026/7/29 9:06:51
Java实现本地Socket通信(三)
今天任务较少也较为简单本节任务账号登录半成品可视化界面一、账号登陆我们知道账号输入操作是需要在客户端进行的所以这里我们需要在客户端封装登陆方法login在这里读取输入并传递给服务端账号信息public void login(OutputStream os){ Scanner scnew Scanner(System.in); System.out.println(请输入账号); String accountsc.nextLine(); byte[] acaccount.getBytes(); try { os.write(ac.length);//不可以发送字符串的长度必须发送字节的长度 os.write(ac); os.flush(); } catch (IOException e) { throw new RuntimeException(e); } }接着我们需要在服务端读取传递过来的信息用封装函数proLogein实现并返回读取到的用户名public String proLogein(Socket socket){ try { InputStream issocket.getInputStream(); int lenis.read(); byte[] msgsnew byte[len]; is.read(msgs); String userNamenew String(msgs); System.out.println(用户userName登录了); return userName; } catch (IOException e) { throw new RuntimeException(e); } }tips.这里proLogein方法应该在消息处理方法proClintMsg处创建线程时调用如下public void proClintMsg(Socket socket){ //注意循环速度太快导致cpu被占满io流根本没机会运行所以这里加一个println让cpu空闲下来 new Thread(()-{ //登录 //读取用户名 String UserNameproLogein(socket); ClientUser cunew ClientUser(UserName,socket); //保存ClientUser对象 SocketList.add(cu); while(true) { try { InputStream iscu.socket.getInputStream(); System.out.println(监听cu.socket.getPort()消息中);//顺序不对 String msgreceive(is); replyMsg(cu,msg); } catch (IOException e) { throw new RuntimeException(e); } } }).start(); }用户信息类Client内部定义了账号account用户名和套接字socket这里就不展示代码了至此用户登录的功能雏形便完成了二、实现界面可视化这里我们需要创建一个UI类ClientUI首先先创建窗口对象并调用内部函数设置相关参数尺寸、关闭方法、显示格式、布局等JFrame jfnew JFrame(聊天室); jf.setSize(500,600); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭 jf.setLocationRelativeTo(null);//居中显示 //默认边框布局随后添加相关组件最后记得设置可见文本显示JTextAreaJTextArea msgAreanew JTextArea();//支持多行显示所以不用jtext显示文字 JScrollPane scrollPanenew JScrollPane(msgArea);//滚动显示面板 jf.add(scrollPane, BorderLayout.NORTH);输入框JTestFieldJTextField msgFieldnew JTextField();//输入框 msgField.setPreferredSize(new Dimension(400,0)); msgField.setBackground(Color.LIGHT_GRAY); jf.add(msgField, BorderLayout.WEST);发送键JButtonJButton sendButtonnew JButton(发送); sendButton.setPreferredSize(new Dimension(100,0)); jf.add(sendButton, BorderLayout.EAST);tips.这里不要忘记为按钮添加监听方法下面是新版本的简便写法sendButton.addActionListener(e - sendMsg(msgArea,msgField)); //e相当于是内部类创建一个临时内部类可以直接调用本类中的函数不需要单独写一个监听类到这里界面基本就创建完成了接下来需要做的便是功能迁移三、功能迁移我们的代码大体上是不需要做什么改动的现在我们需要做的是读取可视化界面内输入框里的内容并让其显示在文本框上消息发送方法如下public void sendMsg(JTextArea msgArea,JTextField msgField){ String msgmsgField.getText(); //send(msg); System.out.println(发送中...); //设置到自己的界面上 msgArea.append(我msg\n); //发送消息 client.send(msg); }显示如下在showui中添加新线程new Thread(()-{ while(true) { String msgclient.readMsg(); // System.out.print(接收消息); // System.out.println(msg); // System.out.println(请输入); msgArea.append(msg\n); } }).start();四、完整代码·Clientimport java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; public class Client { //由于外部需要访问socket所以定义为全局变量 Socket socketnull; public void init(){ try { socketnew Socket(127.0.0.1,54321); login(socket.getOutputStream()); } catch (Exception e) { throw new RuntimeException(e); } } public void send(String message){ try { OutputStream ossocket.getOutputStream(); byte[] msgsmessage.getBytes(); int lenmsgs.length; os.write(len); os.write(msgs); os.flush(); } catch (Exception e) { throw new RuntimeException(e); } } public String readMsg(){ try { InputStream issocket.getInputStream(); int lenis.read(); byte[] msgsnew byte[len]; is.read(msgs); return new String(msgs); } catch (Exception e) { throw new RuntimeException(e); } } public void login(OutputStream os){ Scanner scnew Scanner(System.in); System.out.println(请输入账号); String accountsc.nextLine(); byte[] acaccount.getBytes(); try { os.write(ac.length);//不可以发送字符串的长度必须发送字节的长度 os.write(ac); os.flush(); } catch (IOException e) { throw new RuntimeException(e); } } }·ClientUIimport javax.swing.*; import java.awt.*; import java.util.Scanner; public class ClientUI extends JFrame { Client clientnew Client(); public void showUI(){ //先加载客户端 并进行登录 client.init(); JFrame jfnew JFrame(聊天室); jf.setSize(500,600); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭 jf.setLocationRelativeTo(null);//居中显示 //默认边框布局 JTextArea msgAreanew JTextArea();//支持多行显示所以不用jtext显示文字 // JTextPane msgPanenew JTextPane(msgArea); JScrollPane scrollPanenew JScrollPane(msgArea);//滚动显示 scrollPane.setPreferredSize(new Dimension(0,500)); JTextField msgFieldnew JTextField();//输入框 msgField.setPreferredSize(new Dimension(400,0)); msgField.setBackground(Color.LIGHT_GRAY); JButton sendButtonnew JButton(发送); sendButton.setPreferredSize(new Dimension(100,0)); //JLabel labelnew JLabel(当前状态); jf.add(scrollPane, BorderLayout.NORTH); jf.add(msgField, BorderLayout.WEST); jf.add(sendButton, BorderLayout.EAST); jf.setVisible(true); sendButton.addActionListener(e - sendMsg(msgArea,msgField));//e相当于是内部类创建一个临时内部类可以直接调用本类中的函数不需要单独写一个监听类 new Thread(()-{ while(true) { String msgclient.readMsg(); // System.out.print(接收消息); // System.out.println(msg); // System.out.println(请输入); msgArea.append(msg\n); } }).start(); } public void sendMsg(JTextArea msgArea,JTextField msgField){ String msgmsgField.getText(); //send(msg); System.out.println(发送中...); //设置到自己的界面上 msgArea.append(我msg\n); //发送消息 client.send(msg); } public static void main(String[] args) { ClientUI clientUInew ClientUI(); clientUI.showUI(); } }·ClientUserimport java.net.Socket; public class ClientUser { String account; Socket socket; public ClientUser(String account,Socket socket){ this.accountaccount; this.socketsocket; } public ClientUser(){ } }·Serverimport java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; public class Server { ServerSocket ssnull; ArrayListClientUser SocketListnew ArrayList(); public void init(){ try { ssnew ServerSocket(54321); } catch (IOException e) { throw new RuntimeException(e); } } public Socket listen(){ try { return ss.accept(); } catch (IOException e) { throw new RuntimeException(e); } } public void send(String message, OutputStream os){ try { //mission:通过os把这个消息发送出去 byte[] msgsmessage.getBytes(); int lenmsgs.length; os.write(len);//发送长度 os.write(msgs); os.flush(); } catch (IOException e) { throw new RuntimeException(e); } } public String receive(InputStream is){ try { int lenis.read(); byte[] msgsnew byte[len]; is.read(msgs); // for(int i0;ilen;i){ // msgs[i] (byte) is.read(); // } String msgnew String(msgs); System.out.println(收到msg); return msg; } catch (IOException e) { throw new RuntimeException(e); } } public void replyMsg(ClientUser client,String msg){ //转发消息 for(int i0;iSocketList.size();i){ ClientUser cuSocketList.get(i); Socket scu.socket; if (s!client.socket){ try { String m client.account说msg;//注意拼接逻辑 send(m,s.getOutputStream()); } catch (IOException e) { throw new RuntimeException(e); } } } } public void proClintMsg(Socket socket){ //注意循环速度太快导致cpu被占满io流根本没机会运行所以这里加一个println让cpu空闲下来 new Thread(()-{ //登录 //读取用户名 String UserNameproLogein(socket); ClientUser cunew ClientUser(UserName,socket); //保存ClientUser对象 SocketList.add(cu); while(true) { try { InputStream iscu.socket.getInputStream(); System.out.println(监听cu.socket.getPort()消息中);//顺序不对 String msgreceive(is); replyMsg(cu,msg); } catch (IOException e) { throw new RuntimeException(e); } } }).start(); } public String proLogein(Socket socket){ try { InputStream issocket.getInputStream(); int lenis.read(); byte[] msgsnew byte[len]; is.read(msgs); String userNamenew String(msgs); System.out.println(用户userName登录了); return userName; } catch (IOException e) { throw new RuntimeException(e); } } public static void main(String[] args) { Server servernew Server(); //初始化 server.init(); //匿名内部类放到线程中(监听连接部分) new Thread(()-{ while(true) { System.out.println(等待连接...); Socket s server.listen(); System.out.println(有新的连接s.getInetAddress()s.getPort()); server.proClintMsg(s);//处理客户端消息 每个客户端一个线程 } }).start(); } }