ServerChatMain
package pp.chat;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
//如果一个类,需要有界面的显示,那么该类就需要继承自JFrame,此时,该类就可以被称为一个“窗体类”
//1.定义JFrame窗体中的组件
//2.在构造方法中初始化窗体的组件
//3.使用网络编程完成数据的传输(TCP,UDP协议)
//4.实现“发送”按钮的监听点击事件,需要注意的是,文本域拼接数据时,实现自己换行,不要在发送数据中使用System.lineSeparator()换行。这样会导致无法辨别换行
//5.实现“回车键”发送数据
public class ServerChatMain extends JFrame implements ActionListener,KeyListener{
public static void main(String[] args){
//调用构造方法
new ServerChatMain();
}
//属性
//文本域
private JTextArea jta;
//滚动条
private JScrollPane jsp;
//面板
private JPanel jp;
//文本框
private JTextField jtf;
//按钮
private JButton jb;
//输出流
private BufferedWriter bw = null;
//服务端端口号
private static int serverPort;
//使用static静态代码块读取外部配置文件
//特点1:在类加载的时候,自动执行。
//特点2:一个类只会被加载一次,因此静态代码块在程序中仅会被执行一次。
static{
Properties prop = new Properties();
try{
//加载
prop.load(new FileReader("char.properties"));
//给属性赋值
serverPort = Integer.parseInt(prop.getProperty("serverPort"));
}catch(IOException e){
e.printStackTrace();
}
}
//构造方法
public ServerChatMain(){
//初始化组件
jta = new JTextArea();
//设置文本域默认不可编辑
jta.setEditable(false);
//注意:需要将文本域添加到滚动条中,实现滚动效果
jsp = new JScrollPane(jta);
//面板
jp = new JPanel();
jtf = new JTextField(10);
jb = new JButton("发送");
//注意:需要将文本框与按钮添加到面板中
jp.add(jtf);
jp.add(jb);
//注意:需要将滚动条与面板全部添加到窗体中去
this.add(jsp,BorderLayout.CENTER);
this.add(jp,BorderLayout.SOUTH);
//注意:需要设置“标题,大小,位置,关闭,是否可见
this.setTitle("qq聊天 服务端");
this.setSize(300,300);
this.setLocation(300,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体关闭程序就退出
this.setVisible(true);
/**********************TCP 服务端 start**********************/
//给“发送”按钮绑定一个监听点击事件
jb.addActionListener(this);
//给文本框绑定一个键盘点击事件
jtf.addKeyListener(this);
try{
//1.创建一个服务端的套接字
ServerSocket serverSocket = new ServerSocket(serverPort);
//2.等待客户端的连接
Socket socket = serverSocket.accept();
//3.获取 socket 通道的输入流(输出流是实现读取数据,如何读取?一行一行读取)BufferedReader ->readLine();
//InputStream in = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//4.获取 socket 通道的输出流(输出流实现写出数据,也是写一行,换一行,刷新)BufferedWrite -> newLine();
//问题:什么时候需要写出数据???当用户点击“发送”按钮的时候才需要写出数据
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//循环读取数据,并拼接到文本域中
String line = null;
while((line = br.readLine())!= null){
//将读取的数据拼接到文本域中显示
jta.append(line + System.lineSeparator());
}
//5.关闭 serverSocket 通道
serverSocket.close();
}catch(IOException e1){
e1.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();
}
}
//定义一个方法,实现将数据发送到socket通道中
private void sendDataToSocket(){
//1.获取文本框中发送的内容
String text = jtf.getText();
//2.拼接需要发送的数据内容
text = "服务端对客户端说:" + text;
//3.自己也需要显示
jta.append(text + System.lineSeparator());
try{
//4.发送
bw.write(text);
bw.newLine();
bw.flush();
//5.清空文本框内容
jtf.setText("");
}catch (IOException e1){
e1.printStackTrace();
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
}
ClientChatMain
package pp.chat;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Properties;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ClientChatMain extends JFrame implements ActionListener,KeyListener{
public static void main(String[] args){
//调用构造方法
new ClientChatMain();
}
//属性
//文本域
private JTextArea jta;
//滚动条
private JScrollPane jsp;
//面板
private JPanel jp;
//文本框
private JTextField jtf;
//按钮
private JButton jb;
//输出流
private BufferedWriter bw = null;
//客户端的IP地址
private static String clientIP;
//客户端的port端口号
private static int clientPort;
//静态代码块加载外部配置文件
static{
Properties prop = new Properties();
try{
prop.load(new FileReader("chat,properties"));
clientIP = prop.getProperty("clientIP");
clientPort = Integer.parseInt(prop.getProperty("clientPort"));
}catch(IOException e){
e.printStackTrace();
}
}
//构造方法
public ClientChatMain(){
//初始化组件
jta = new JTextArea();
//设置文本域默认不可编辑
jta.setEditable(false);
//注意:需要将文本域添加到滚动条中,实现滚动效果
jsp = new JScrollPane(jta);
//面板
jp = new JPanel();
jtf = new JTextField(10);
jb = new JButton("发送");
//注意:需要将文本框与按钮添加到面板中
jp.add(jtf);
jp.add(jb);
//注意:需要将滚动条与面板全部添加到窗体中去
this.add(jsp,BorderLayout.CENTER);
this.add(jp,BorderLayout.SOUTH);
//注意:需要设置“标题,大小,位置,关闭,是否可见
this.setTitle("qq聊天 客户端");
this.setSize(300,300);
this.setLocation(600,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
/**********************TCP 客户端 start**********************/
//给发送按钮绑定一个监听点击事件
jb.addActionListener(this);
//给文本框绑定一个键盘点击事件
jtf.addKeyListener(this);
try{
//1.创建一个客户端的套接字(尝试连接)
Socket socket = new Socket(clientIP,clientPort);
//2.获取 socket 通道的输入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//3.获取 socket 通道的输出流
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//循环读取数据,并拼接到文本域中
String line = null;
while((line = br.readLine()) != null){
jta.append(line + System.lineSeparator());
}
//4.关闭 socket 通道
socket.close();
}catch(Exception e){
e.printStackTrace();
}
/**********************TCP 客户端 end**********************/
}
@Override
public void actionPerformed(ActionEvent e) {
sendDataToSocket();
}
//行为
@Override
public void keyPressed(KeyEvent e) {
//回车键
if(e.getKeyCode() == KeyEvent.VK_ENTER){
//发送数据到socket通道
sendDataToSocket();
}
}
private void sendDataToSocket(){
//1.获取文本框中需要发送的数据内容
String text = jtf.getText();
//2.拼接内容
text = "客户端对服务端说:" + text;
//3.自己显示
jta.append(text + System.lineSeparator());
try{
//4.发送
bw.write(text);
//bw.newLine() 与 System.lineSeparator() 两个换行导致使用BufferedReader一行一行读取时,无法正确的辨别需要的换行
bw.newLine();
bw.flush();
//5.清空
jtf.setText("");
}catch (IOException e1){
e1.printStackTrace();
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
}
结果
没有连接成功,不能成功发送消息
并且文本框没有刷新
还有一堆看不懂的