Java编写TCP网络程序案例
要点提示
- 服务端,使ServerSocket对象指定监听的端口号,通过Socket对象获得客户端连接
- 客户端,使用Socket指定IP地址和端口号
- 先运行服务端,再运行客户端,否则会连接失败
- 客户端和服务端最好使用一个不断循环的线程监听输入流,以下使用JFrame界面显示效果
服务端程序源码
package io;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.Vector;
/**
* @author wangzeng
*
*/
public class TcpServer extends JFrame {
JTextField txtInput = new JTextField("", 20);
JButton btnSend = new JButton("发送");
JList<String> lstMsg = new JList<>();
public final static int DEFAULT_PORT = 6543;
protected ServerSocket server = null;
protected Socket sock = null;
protected BufferedReader in = null;
protected PrintWriter out = null;
DefaultListModel<String> lstMsgModel = new DefaultListModel<>();
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new TcpServer().setVisible(true);
});
}
public TcpServer() {
// 标题
this.setTitle("服务器");
this.setSize(400, 800);
// 设置居中
this.setLocationRelativeTo(null);
// JPanel默认FlowLayout布局
JPanel southPanel = new JPanel();
southPanel.add(txtInput);
southPanel.add(btnSend);
// Container默认BorderLayout布局
Container content = this.getContentPane();
content.add(southPanel, BorderLayout.SOUTH);
// 把DefaultList添加到JList组件
lstMsg.setModel(lstMsgModel);
// 把JList组件加入JScrollPane容器,再把JScrollPane添加到content容器
// 使用new JScrollPane.add(lstMsg)会出现不能显示问题
content.add(new JScrollPane(lstMsg), BorderLayout.CENTER);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
try {
// 使用ServerSocket创建服务器套接字
server = new ServerSocket(DEFAULT_PORT);
} catch (IOException e) {
System.out.println("server:套接字失败");
// e.printStackTrace();
}
// JButton点击事件:发送信息到客户端
btnSend.addActionListener((e) -> {
String str = txtInput.getText();
// sock可能null
if(out!=null) {
out.println(str);
out.flush();
// 显示到界面
showMessage(str);
}
});
// 监听客户端的线程
new Thread(() -> {
try {
// 等待响应
sock = server.accept();
System.out.println("server:客户端链接成功");
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
while (true) {
try {
in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
out = new PrintWriter(sock.getOutputStream());
showMessage(in.readLine());
} catch (IOException e1) {
// TODO Auto-generated catch block
// e1.printStackTrace();
try {
// accept会阻塞线程,直到有客户端连接才会继续执行
sock = server.accept();
System.out.println("server:正在尝试再次连接客户端");
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
}
}
}).start();
}
// 显示信息
public void showMessage(String str) {
if(str!="") {
SwingUtilities.invokeLater(() -> {
// 添加到DefaultListModel中
lstMsgModel.addElement(str);
});
}
}
}
客户端程序源码
package io;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
import java.net.*;
import java.io.*;
public class TcpClient extends JFrame {
JTextField txtInput = new JTextField("", 20);
JButton btnSend = new JButton("发送");
JList<String> lstMsg = new JList<>();
DefaultListModel<String> lstMsgModel = new DefaultListModel<>();
Socket sock;
BufferedReader in;
PrintWriter out;
public final static int DEFAULT_PORT = 6543;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new TcpClient().setVisible(true);
});
}
public TcpClient() {
this.setTitle("客户端");
this.setSize(400, 800);
// this.setBounds(500, 500, 600, 540);
Container content = this.getContentPane();
content.add(new JScrollPane(lstMsg), BorderLayout.CENTER);
JPanel nothPanel = new JPanel();
nothPanel.add(txtInput);
nothPanel.add(btnSend);
content.add(nothPanel, BorderLayout.SOUTH);
lstMsg.setModel(lstMsgModel);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
// 创建套接字
try {
sock = new Socket("127.0.0.1", DEFAULT_PORT);
showMessage("客户端创建套接字成功");
} catch (IOException e) {
// e.printStackTrace();
showMessage("Connection failed");
}
// 发送按钮:向服务器发送信息
btnSend.addActionListener(e -> {
if (txtInput.getText().length() != 0) {
String msg = txtInput.getText();
out.println(msg);
out.flush();
showMessage(msg);
System.out.println("ChatClient.init():" + txtInput);
}
});
// 监听服务器消息线程
new Thread(() -> {
while (true) {
try {
out = new PrintWriter(sock.getOutputStream());
in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String msg = in.readLine();
showMessage(msg);
} catch (IOException e1) {
// TODO Auto-generated catch block
// e1.printStackTrace();
System.out.println("Client:服务器出现异常2");
if(in!=null) {
try {
in.close();
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
}
if(out!=null) {
out.close();
}
try {
sock.close();
System.out.println("client:正在关闭");
// 服务端中断后客户端结束while
break;
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
}
}
}).start();
}
// 显示消息
public void showMessage(String str) {
if(str!="") {
SwingUtilities.invokeLater(() -> {
lstMsgModel.addElement(str);
});
}
}
}