19.2 TCP程序设计基础
1、InetAddress类
java.net包中的inetAddress类是与IP地址相关的类,利用该类可以获取IP地址、主机地址等信息。
InetAddress类的常用方法如下:
方法 | 返回值 | 说明 |
getByName(String host) | InetAddress | 获取与Host相对应的InetAddress对象 |
getHostAddress() | String | 获取InetAddress对象所包含的IP地址 |
getHostName() | String | 获取此IP地址的主机名 |
getLocalHost() | InetAddress | 返回本地主机的InetAddress对象 |
注意:InetAddress类的方法会抛出UnknownHostException异常,所以必须进行异常处理。这个异常在主机不存在或网络连接错误时发生。
2、ServerSocket类
java.net包中的ServerSocket类用于表示服务器套接字,其主要功能是等待来自网络上的“请求”,它可通过制定的端口来等待连接的套接字。服务器套接字依次可以与一个套接字连接。如果多台客户机同时提出连接请求,服务器套接字会将请求连接的客户机存入队列中,然后从中取出一个套接字,与服务器新建的套接字连接起来。若请求连接数大于最大容纳数,则多出的连接请求被拒绝。队列的默认大小是50.
ServerSocket类的构造方法都抛出IOException异常,分别有以下几种形式:
ServerSocket():创建非绑定服务器套接字
ServerSocket(int port):创建绑定到特定端口的服务器套接字
ServerSocket(int port, int backlog):利用指定的backlog创建服务器套接字并将其绑定到指定的本地端口号
ServerSocket(int prot, int backlog, InetAddress bindAddress):使用指定的端口、侦听backlog和要绑定到的本地IP地址创建服务器。这种情况适用于极端及上有多块网卡和多个IP地址的情况,用于可以明确规定ServerSocket在哪块网卡或IP地址上等待客户的连接请求。
ServerSocket类的常用方法如下:
方法 | 返回值 | 说 明 |
accept() | Socket | 等待客户机的连接。若连接,则创建一套接字 |
isBound() | boolean | 判断ServerSocket的绑定状态 |
getInetAddress() | InetAddress | 返回此服务器套接字的本地地址 |
isClosed() | boolean | 返回服务器套接字的关闭状态 |
close() | void | 关闭服务器套接字 |
bind(SocketAddress endpoint) | void | 将ServerSocket绑定到特定地址(IP地址和端口号) |
getInetAddress() | int | 返回服务器套接字等待的端口号 |
调用ServerSocket类的accept()方法会返回一个和客户端Socket对象向连接的Socket对象,服务器的Socket对象使用getOutputStream()方法获得的输出流将指向客户端Socket对象使用getInputStream()方法获得的那个输入流;同样,服务器端的Socket对象使用getInputStream()方法获得的输入流将指向客户端Socket对象使用getOutputStream()方法获得的那个输出流。也就是说,当服务器向输出流协议信息时,客户端通过相应的输入流就能读取,反之亦然。
注意:(1)、accept()方法会阻塞线程的继续执行,知道接收到客户的呼叫。如果没有客户呼叫服务器,那么System.out.print(“连接中”)语句将不会执行。语句如果没有客户请求,accept()方法没有发生阻塞,肯定是程序出现了问题。通常是使用了一个还在被其它程序占用的端口号,ServerSoket绑定没有成功。
(2)、当一台机器上安装了多个网络应用程序时,很可能指定的端口号已被占用。还可能遇到以前运行良好的网络程序突然运行不了的情况,这种情况很可能也是由于端口被别的程序韩勇了。此时可以运行netstat -an来查看该程序锁使用的端口号是否被占用。
3、相关参考例子

1 package com.lzw; 2 3 import java.io.*; 4 import java.net.*; 5 6 public class MyTcp { // 创建类MyTcp 7 private BufferedReader reader; // 创建BufferedReader对象 8 private ServerSocket server; // 创建ServerSocket对象 9 private Socket socket; // 创建Socket对象socket 10 11 void getserver() { 12 try { 13 server = new ServerSocket(8998); // 实例化Socket对象 14 System.out.println("服务器套接字已经创建成功"); // 输出信息 15 while (true) { // 如果套接字是连接状态 16 System.out.println("等待客户机的连接"); // 输出信息 17 socket = server.accept(); // 实例化Socket对象 18 reader = new BufferedReader(new InputStreamReader(socket 19 .getInputStream())); // 实例化BufferedReader对象 20 getClientMessage(); // 调用getClientMessage()方法 21 } 22 } catch (Exception e) { 23 e.printStackTrace(); // 输出异常信息 24 } 25 } 26 27 private void getClientMessage() { 28 try { 29 while (true) { // 如果套接字是连接状态 30 if (reader.ready()) { 31 // 获得客户端信息 32 System.out.println("客户机:" + reader.readLine()); 33 } 34 } 35 } catch (Exception e) { 36 e.printStackTrace(); // 输出异常信息 37 } 38 try { 39 if (reader != null) { 40 reader.close(); // 关闭流 41 } 42 if (socket != null) { 43 socket.close(); // 关闭套接字 44 } 45 } catch (IOException e) { 46 e.printStackTrace(); 47 } 48 } 49 50 public static void main(String[] args) { // 主方法 51 MyTcp tcp = new MyTcp(); // 创建本类对象 52 tcp.getserver(); // 调用方法 53 } 54 }

1 package com.lzw; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.io.*; 6 import java.net.*; 7 8 import javax.swing.*; 9 import javax.swing.border.*; 10 11 public class MyClien extends JFrame { // 创建类继承JFrame类 12 /** 13 * 14 */ 15 private static final long serialVersionUID = 1L; 16 private PrintWriter writer; // 声明PrintWriter类对象 17 Socket socket; // 声明Socket对象 18 private JTextArea ta = new JTextArea(); // 创建JtextArea对象 19 private JTextField tf = new JTextField(); // 创建JtextField对象 20 Container cc; // 声明Container对象 21 22 public MyClien(String title) { // 构造方法 23 super(title); // 调用父类的构造方法 24 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 25 cc = this.getContentPane(); // 实例化对象 26 27 final JScrollPane scrollPane = new JScrollPane(); 28 scrollPane.setBorder(new BevelBorder(BevelBorder.RAISED)); 29 getContentPane().add(scrollPane, BorderLayout.CENTER); 30 scrollPane.setViewportView(ta); 31 cc.add(tf, "South"); // 将文本框放在窗体的下部 32 tf.addActionListener(new ActionListener() { 33 // 绑定事件 34 public void actionPerformed(ActionEvent e) { 35 // 将文本框中信息写入流 36 writer.println(tf.getText()); 37 // 将文本框中信息显示在文本域中 38 ta.append(tf.getText() + '\n'); 39 ta.setSelectionEnd(ta.getText().length()); 40 tf.setText(""); // 将文本框清空 41 } 42 }); 43 } 44 45 private void connect() { // 连接套接字方法 46 ta.append("尝试连接\n"); // 文本域中提示信息 47 try { // 捕捉异常 48 socket = new Socket("127.0.0.1", 8998); // 实例化Socket对象 49 writer = new PrintWriter(socket.getOutputStream(), true); 50 ta.append("完成连接\n"); // 文本域中提示信息 51 } catch (Exception e) { 52 e.printStackTrace(); // 输出异常信息 53 } 54 } 55 56 public static void main(String[] args) { // 主方法 57 MyClien clien = new MyClien("向服务器送数据"); // 创建本例对象 58 clien.setSize(200, 200); // 设置窗体大小 59 clien.setVisible(true); // 将窗体显示 60 clien.connect(); // 调用连接方法 61 } 62 }

1 package com.lzw; 2 3 import java.net.*; 4 5 public class MyHost { 6 public static void main(String args[]) { 7 InetAddress ip = null; 8 9 try { 10 ip = InetAddress.getByName("localhost");// 修改为指定的主机名称 11 System.out.println("主机名:" + ip.getHostName()); 12 System.out.println("主机IP地址:" + ip.getHostAddress()); 13 System.out.println("本机IP地址:" 14 + InetAddress.getLocalHost().getHostAddress()); 15 } catch (UnknownHostException e) { 16 e.printStackTrace(); 17 } 18 19 } 20 }

1 package com.lzw; 2 3 import java.io.*; 4 import java.net.*; 5 6 /** 7 * @author Administrator 8 */ 9 public class ComputerServer { 10 public static void main(String[] args) { 11 try { 12 ServerSocket ss = new ServerSocket(8001); 13 while (!ss.isClosed()) { 14 Socket s = ss.accept(); 15 InputStream ips = s.getInputStream(); 16 OutputStream ops = s.getOutputStream(); 17 String str = "欢迎进入程序\n2.编写TCP服务器程序," 18 + "实现创建一个在8001端口上等待的ServerSocket" 19 + "对象,当接收到一个客户机的连接请求后," 20 + "程序从与客户机建立了连接的Socket对象中获得输入输出" 21 + "流。通过输出流向客户机发送信息。"; 22 ops.write(str.getBytes()); 23 byte[] buf = new byte[1024]; 24 int len = 0; 25 if (ips.available() > 0) 26 len = ips.read(buf); 27 System.out.println(new String(buf, 0, len)); 28 ips.close(); 29 ops.close(); 30 s.close(); 31 } 32 ss.close(); 33 } catch (IOException e) { 34 e.printStackTrace(); 35 } 36 } 37 }

1 package com.lzw; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.io.*; 6 import java.net.*; 7 8 import javax.swing.*; 9 10 public class TestClient extends JFrame { 11 12 /** 13 * 14 */ 15 private static final long serialVersionUID = 1L; 16 private JTextArea textArea; 17 private JTextField portField; 18 private JTextField hostField; 19 20 /** 21 * Launch the application 22 * 23 * @param args 24 */ 25 public static void main(String args[]) { 26 EventQueue.invokeLater(new Runnable() { 27 public void run() { 28 try { 29 TestClient frame = new TestClient(); 30 frame.setVisible(true); 31 } catch (Exception e) { 32 e.printStackTrace(); 33 } 34 } 35 }); 36 } 37 38 /** 39 * Create the frame 40 */ 41 public TestClient() { 42 super(); 43 setBounds(100, 100, 500, 212); 44 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 45 46 final JPanel panel = new JPanel(); 47 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); 48 getContentPane().add(panel, BorderLayout.NORTH); 49 50 final JLabel label = new JLabel(); 51 label.setText("连接主机:"); 52 panel.add(label); 53 54 hostField = new JTextField(); 55 hostField.setText("localhost"); 56 panel.add(hostField); 57 58 final JLabel label_1 = new JLabel(); 59 label_1.setText("端口:"); 60 panel.add(label_1); 61 62 portField = new JTextField(); 63 portField.setText("8001"); 64 panel.add(portField); 65 66 final JButton button = new JButton(); 67 button.addActionListener(new ActionListener() { 68 public void actionPerformed(final ActionEvent e) { 69 final String hostName = hostField.getText(); 70 String portNum = portField.getText(); 71 final int port = Integer.parseInt(portNum); 72 new Thread() { 73 public void run() { 74 try { 75 final InetAddress host = InetAddress.getByName(hostName); 76 Socket socket = new Socket(host, port); 77 final InputStream is = socket.getInputStream(); 78 InputStreamReader reader=new InputStreamReader(is); 79 int data = 0; 80 while ((data=reader.read()) != -1) { 81 textArea.append((char)data+""); 82 textArea.revalidate(); 83 Thread.sleep(100); 84 } 85 } catch (Exception e1) { 86 textArea.append(e1.toString()); 87 e1.printStackTrace(); 88 } 89 } 90 }.start(); 91 92 } 93 }); 94 button.setText("连接"); 95 panel.add(button); 96 97 final JScrollPane scrollPane = new JScrollPane(); 98 getContentPane().add(scrollPane, BorderLayout.CENTER); 99 100 textArea = new JTextArea(); 101 textArea.setLineWrap(true); 102 scrollPane.setViewportView(textArea); 103 } 104 }

1 package com.lzw; 2 3 //服务器端程序 4 import java.awt.*; 5 import java.io.*; 6 import java.net.*; 7 import java.util.*; 8 import java.util.List; 9 10 import javax.swing.*; 11 12 public class TCPServer extends JFrame { 13 /** 14 * 15 */ 16 private static final long serialVersionUID = 1L; 17 private ServerSocket ss = null; 18 private boolean bStart = false; 19 20 private JTextArea taContent = new JTextArea(); 21 22 private int index = 0; 23 24 List<Client> clients = new ArrayList<Client>(); 25 26 public void launchFrame() { 27 // Container con = this.getContentPane(); 28 taContent.setEditable(false); 29 30 taContent.setBackground(Color.DARK_GRAY); 31 taContent.setForeground(Color.YELLOW); 32 this.add(taContent); 33 this.setSize(300, 350); 34 this.setLocation(400, 200); 35 this.setTitle("TCP Server"); 36 this.setVisible(true); 37 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 38 tcpMonitor(); 39 } 40 41 public void tcpMonitor() { 42 try { 43 ss = new ServerSocket(8888); 44 bStart = true; 45 } catch (IOException e) { 46 47 e.printStackTrace(); 48 } 49 50 try { 51 while (bStart) { 52 index++; 53 Socket s = ss.accept(); 54 Client c = new Client(s); 55 clients.add(c); 56 57 taContent.append(s.getInetAddress().getHostAddress() 58 + " connected " + index + " clients\n"); 59 new Thread(c).start(); 60 61 } 62 } catch (IOException e) { 63 e.printStackTrace(); 64 } finally { 65 try { 66 ss.close(); 67 } catch (IOException e) { 68 69 e.printStackTrace(); 70 } 71 } 72 73 } 74 75 public static void main(String args[]) { 76 TCPServer ts = new TCPServer(); 77 ts.launchFrame(); 78 } 79 80 private class Client implements Runnable { 81 DataInputStream dis = null; 82 DataOutputStream dos = null; 83 84 Socket s = null; 85 boolean bStart = false; 86 87 Client(Socket s) { 88 this.s = s; 89 try { 90 dis = new DataInputStream(s.getInputStream()); 91 dos = new DataOutputStream(s.getOutputStream()); 92 } catch (IOException e) { 93 e.printStackTrace(); 94 } 95 96 bStart = true; 97 } 98 99 public void sendToEveryClient(String str) { 100 try { 101 dos.writeUTF(str); 102 dos.flush(); 103 104 } catch (IOException e) { 105 index--; 106 clients.remove(this); 107 taContent.append(s.getInetAddress().getHostAddress() 108 + " exited " + index + " clients\n"); 109 System.out.println("对方退出了!我从List里面去掉了!"); 110 } 111 } 112 113 public void run() { 114 try { 115 while (bStart) { 116 String str = dis.readUTF(); 117 System.out.println(str); 118 for (int i = 0; i < clients.size(); i++) { 119 Client c = clients.get(i); 120 c.sendToEveryClient(str); 121 } 122 } 123 } catch (EOFException e) { 124 clients.remove(this); 125 taContent.append(s.getInetAddress().getHostAddress() 126 + " exited " + clients.size() + " clients\n"); 127 System.out.println("client closed"); 128 } catch (SocketException e) { 129 System.out.println("client closed"); 130 } catch (IOException e) { 131 e.printStackTrace(); 132 } finally { 133 try { 134 if (s != null) 135 s.close(); 136 if (dis != null) 137 dis.close(); 138 if (dos != null) 139 dos.close(); 140 } catch (IOException e) { 141 e.printStackTrace(); 142 } 143 } 144 } 145 146 } 147 148 }

1 package com.lzw; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.io.*; 6 import java.net.*; 7 8 import javax.swing.*; 9 10 public class TCPClient extends JFrame { 11 /** 12 * 13 */ 14 private static final long serialVersionUID = 1L; 15 TextArea taContent = new TextArea(); 16 JTextField tfTxt = new JTextField(20); 17 18 JButton send = new JButton("发送"); 19 JButton connect = new JButton("连接"); 20 JButton clear = new JButton("清空"); 21 22 boolean live = false; 23 JPanel p1 = new JPanel(); 24 JPanel p2 = new JPanel(); 25 26 Socket s = null; 27 DataOutputStream dos = null; 28 DataInputStream dis = null; 29 30 boolean bConnected = false; 31 32 Thread t = new Thread(new RecToServer()); 33 34 public void launchFrame() { 35 36 taContent.setEditable(false); 37 38 p2.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 5)); 39 p2.add(send); 40 p2.add(connect); 41 p2.add(clear); 42 43 Container con = this.getContentPane(); 44 45 con.add(taContent, "North"); 46 con.add(tfTxt, "Center"); 47 con.add(p2, "South"); 48 49 this.setSize(300, 350); 50 this.setLocation(400, 200); 51 this.setTitle("Chat Client"); 52 53 this.setVisible(true); 54 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 55 56 connect.addActionListener(new Connect()); 57 send.addActionListener(new SendMsg()); 58 clear.addActionListener(new ActionListener() { 59 public void actionPerformed(ActionEvent e) { 60 taContent.setText(""); 61 } 62 }); 63 } 64 65 public void connectToServer() { 66 try { 67 68 s = new Socket("127.0.0.1", 8888); 69 dos = new DataOutputStream(s.getOutputStream()); 70 dis = new DataInputStream(s.getInputStream()); 71 72 bConnected = true; 73 74 } catch (BindException e) { 75 System.out.println("找不到指定的服务器"); 76 } catch (UnknownHostException e) { 77 // TODO Auto-generated catch block 78 e.printStackTrace(); 79 } catch (IOException e) { 80 // TODO Auto-generated catch block 81 e.printStackTrace(); 82 } 83 84 } 85 86 public void disConnect() { 87 try { 88 if (s != null) { 89 s.close(); 90 } 91 92 if (dos != null) { 93 dos.close(); 94 } 95 if (dis != null) { 96 dis.close(); 97 } 98 } catch (IOException e) { 99 e.printStackTrace(); 100 } 101 } 102 103 public static void main(String args[]) { 104 TCPClient tc = new TCPClient(); 105 tc.launchFrame(); 106 } 107 108 private class Connect implements ActionListener { 109 public void actionPerformed(ActionEvent e) { 110 if (e.getActionCommand() == "连接") { 111 112 connectToServer(); 113 try { 114 t.start(); 115 } catch (IllegalThreadStateException ex) { 116 117 } 118 119 connect.setText("断开连接"); 120 121 } else if (e.getActionCommand() == "断开连接") { 122 disConnect(); 123 connect.setText("连接"); 124 } 125 126 } 127 } 128 129 private class SendMsg implements ActionListener { 130 public void actionPerformed(ActionEvent e) { 131 if (connect.getActionCommand() == "连接") { 132 JOptionPane.showMessageDialog(TCPClient.this, 133 "没有找到指定的服务器", "错误提示", 1); 134 } else { 135 String str = tfTxt.getText(); 136 tfTxt.setText(""); 137 138 try { 139 dos.writeUTF(str); 140 dos.flush(); 141 } catch (SocketException ex) { 142 System.out.println("没有找到指定的服务器"); 143 JOptionPane.showMessageDialog(TCPClient.this, 144 "没有找到指定的服务器", "错误提示", 1); 145 } catch (IOException ex) { 146 ex.printStackTrace(); 147 } 148 } 149 150 } 151 } 152 153 private class RecToServer implements Runnable { 154 public void run() { 155 try { 156 while (bConnected) { 157 String str = dis.readUTF(); 158 // System.out.println(str); 159 160 taContent.append(str + "\n"); 161 } 162 } catch (SocketException e) { 163 System.out.println("服务器已关闭"); 164 } catch (IOException e) { 165 e.printStackTrace(); 166 } 167 } 168 } 169 }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 大模型 Token 究竟是啥:图解大模型Token
· 35岁程序员的中年求职记:四次碰壁后的深度反思
· 继承的思维:从思维模式到架构设计的深度解析
· 如何在 .NET 中 使用 ANTLR4
· 后端思维之高并发处理方案
· BotSharp + MCP 三步实现智能体开发
· BotSharp 5.0 MCP:迈向更开放的AI Agent框架
· 5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
· 【ESP32】两种模拟 USB 鼠标的方法
· 设计模式脉络