目录
项目结构
TCP
窗体组成
server
package cn.itcast.chat;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
// 服务端类
// 如果一个类需要窗口界面的显示,那么该类就需要继承JFrame,该类就可以被称为而窗体类
// 1.定义窗体类组件
// 2.在构造方法中初始化属性
// 3.使用网络编程实现数据传输 (TCP,UDP 协议)
// 4.实现发送按钮的监听点击事件
//需要注意的是,文本域拼接数据时,实现自己换行,不要在发送数据中使用 Svstem.ineSeparator( 换行)
// 5.实现回车键发送数据
public class ServerChatMain extends JFrame implements ActionListener, KeyListener {
public static void main(String[] args) {
new ServerChatMain();
}
//属性
//文本域
private JTextArea jTextArea;
//滚动条
private JScrollPane jScrollPane;
//面板
private JPanel jPanel;
//文本框(发送消息)
private JTextField jTextField;
//按钮(发送)
private JButton jButton;
//输出流
private BufferedWriter bufferedWriter ;
//服务端端口号
private static int serverPort;
// 使用 static 静态代码块读取配置文件
// 特点1.在类加载的时候,自动执行
// 特点2,一个类只会被加载一次,因此静态代码块只会被执行一次
static {
Properties properties = new Properties();
try {
// 加载
properties.load(new FileReader("chat.properties"));
// 给属性赋值
serverPort = Integer.parseInt(properties.getProperty("serverPort"));
} catch (IOException e) {
e.printStackTrace();
}
}
//构造方法初
public ServerChatMain() {
//始化组件
//文本域
jTextArea = new JTextArea();
jTextArea.setEditable(false);//设置文本域不可编辑(默认),所以注释掉
// 将文本域添加到滚动条中,实现滚动效果
jScrollPane = new JScrollPane(jTextArea);
//面板
jPanel = new JPanel();
//文本框长度10
jTextField = new JTextField(20);
//按钮
jButton = new JButton("发送");
// 将文本框和按钮添加到面板中
jPanel.add(jTextField);
jPanel.add(jButton);
//将滚动条和面板全部添加到窗体中
this.add(jScrollPane,BorderLayout.CENTER);//添加到中间
this.add(jPanel,BorderLayout.SOUTH);//下面
// 设置 标题、大小、标题、位置、关闭、是否可见
this.setTitle("QQ聊天,服务端");
this.setSize(500,500);
this.setLocation(300,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体关闭就退出
this.setVisible(true);
/***************** TCP 服务端 star *************************/
//给发送按钮绑定一个监听点击事件 需要实现 ActionListener 接口,重写方法
jButton.addActionListener(this);
// 给文本框绑定一个键盘点击事件 需要实现 KeyListener 接口,重写方法 keyPressed()
jTextField.addKeyListener(this);
try {
// 1.创建服务端套接字
ServerSocket serverSocket = new ServerSocket(serverPort);
// 2.等待客户端的连接
Socket socket = serverSocket.accept();
// 4.获取socket 通道的输出流 (输出流实现写出数据,也是写一行,换一行,刷新) Bufferedwriter -> newLine();
// 问题 : 什么时候需要写出数据??? 当用户点击~发送~ 按的时候才需要写出数据
bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 3.获取socket 通道的输入流
// 输出流是实现读取数据,如何读取 ??? 一行一行读取) 所以用 BufferedReader 类的 -> readLine()方法;
InputStream input = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input));
// 循环读取数据、并拼接到文本域中
String line = null;
System.out.println("............... " + bufferedReader.readLine());
while ((line =bufferedReader.readLine()) != null){
System.out.println("line: " + line);
//将读取的数据拼接到上面文本域中显示
jTextArea.append(line + System.lineSeparator());
}
// 5.关闭 serverSocket 通道
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
/***************** TCP 服务端 end **************************/
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("发送按钮点击、进入了监听方法。。。。。");
sendDataToSocket();
}
// 按下
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER){ //回车键
System.out.println(e);//可以敲击不同的按键查看其 keyCode、keyText...
sendDataToSocket();
}
}
// 定义一个方法、将数据发送到 socket 通道中去
private void sendDataToSocket(){
// 1. 获取文本框中的发送内容
String text = jTextField.getText();
// 2. 拼接需要发送的内容数据
text = "服务端对客户端说: " + text;
// 3. 自己的文本域中显示
jTextArea.append(text + System.lineSeparator());
System.out.println("server: " + text);
try {
// 4. 发送 (这里需要用到 bufferedWriter 所以是字段)
bufferedWriter.write(text);
bufferedWriter.newLine();//换行
bufferedWriter.flush();//刷新
// 5. 清空文本框
jTextField.setText("");
} catch (IOException ex) {
ex.printStackTrace();
}
}
// 被敲击
@Override
public void keyTyped(KeyEvent e) {
}
// 松开
@Override
public void keyReleased(KeyEvent e) {
}
}
client
package cn.itcast.chat;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.net.Socket;
import java.util.Properties;
public class ClientChatMain extends JFrame implements ActionListener, KeyListener {
public static void main(String[] args) {
new ClientChatMain();
}
//属性
//文本域
private JTextArea jTextArea;
//滚动条
private JScrollPane jScrollPane;
//面板
private JPanel jPanel;
//文本框(发送消息)
private JTextField jTextField;
//按钮(发送)
private JButton jButton;
// 输出流
BufferedWriter bufferedWriter = null;
// 客户端 ip地址
private static String clientIP;
// 客户端 port端口号
private static int clientPort;
static {
Properties properties = new Properties();
try {
// 加载
properties.load(new FileReader("chat.properties"));
// 给属性赋值
clientIP = properties.getProperty("clientIP");
clientPort = Integer.parseInt(properties.getProperty("clientPort"));
} catch (IOException e) {
e.printStackTrace();
}
}
//构造方法初
public ClientChatMain() {
//始化组件
//文本域
jTextArea = new JTextArea();
jTextArea.setEditable(false);//设置文本域不可编辑(默认),所以注释掉
// 将文本域添加到滚动条中,实现滚动效果
jScrollPane = new JScrollPane(jTextArea);
//面板
jPanel = new JPanel();
//文本框长度10
jTextField = new JTextField(20);
//按钮
jButton = new JButton("发送");
// 将文本框和按钮添加到面板中
jPanel.add(jTextField);
jPanel.add(jButton);
//将滚动条和面板全部添加到窗体中
this.add(jScrollPane, BorderLayout.CENTER);//添加到中间
this.add(jPanel,BorderLayout.SOUTH);//下面
// 设置 标题、大小、标题、位置、关闭、是否可见
this.setTitle("QQ聊天,客户端");
this.setSize(500,500);
this.setLocation(900,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体关闭就退出
this.setVisible(true);
/***************** TCP 客户端 star *************************/
// 给发送按钮绑定一个监听事件
jButton.addActionListener(this);
// 给文本框绑定一个键盘点击事件
jTextField.addKeyListener(this);
try {
// 1.创建客户端套接字(并且自动尝试连接)
Socket socket = new Socket(clientIP, clientPort);
// 2.获取socket 通道的输入流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 3.获取socket 通道的输出流
bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 循环读取数据、并拼接到文本域中
String line = null;
while ((line = bufferedReader.readLine()) != null){
System.out.println("client: " + line);
jTextArea.append(line + System.lineSeparator());
}
// 4.关闭socket通道
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
/***************** TCP 客户端 end **************************/
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("发送按钮点击,进入了客户端.....");
sendDataToSocket();
}
// 按下
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER){
// 将数据发送到socket通道
sendDataToSocket();
}
}
private void sendDataToSocket() {
// 1. 获取文本框中需要发送的数据内容
String text = jTextField.getText();
// 2. 拼接内容
text = "客户端对服务端说: " + text;
// 3. 自己显示
jTextArea.append(text + System.lineSeparator());
try {
// 4. 发送
bufferedWriter.write(text);
bufferedWriter.newLine();
bufferedWriter.flush();
// 5. 清空
jTextField.setText("");
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
properties
serverPort=8888
clientIP=127.0.0.1
clientPort=8888