目录
聊天程序
1.TCP协议
1.1.TCP三次握手
1.2.Java编程
?1.3.完整功能实现
?2.总结
聊天程序
1.TCP协议
我们都知道远程连接到一个应用需要确认IP地址和端口,过多的底层原理就不必多说,直接网络编程的实现,TCP协议连接安全且传输的大型数据(如图片、视频)完整,UDP协议连接不安全且传输的大型数据不完整,导致传出去的图片、视频播放不出来
1.1.TCP三次握手
- 第一次握手是客户端向服务端发起请求连接信息
- 第二次握手是服务端接收到请求并且发送响应给客户端
- 第三次握手是客户端接收到响应后再给服务端发信息,完成连接
具体在下面代码完成后讲解
1.2.Java编程
Java建立TCP协议用到两个类:
-
Socket类:作为客户端应用所用到的类,用于确认连接的服务器(设置IP地址和端口),用于数据的发送与接收 Socket sk= new Socket("127.0.0.1",1200);
//连接到的服务器IP地址为12.0.0.1,连接到服务器应用的端口为1200 -
ServerSocket类:这是作为服务端应用所用到的类,设置连接端口,接受客户端的发送请求 ServerSocket ss = new ServerSocket(1200); //设置服务端的端口为1200
Socket sk = ss.accept(); //转化为Socket对象 - 数据之间以字节传输,所以传输的数据完整,但也可转化成字符流传输方式,客户端与服务端之间传输信息是以写的方式发送信息,以读的方式接收信息,如下:
Socket sk= new Socket("127.0.0.1",1200);
OutputStreamWriter out=new OutputStreamWriter(sk.getOutputStream());
//通过sk.getOutputStream()方式(网络方式)以OutputStreamWriter(字节流)输出信息
//同理如下
InputStreamReader in=new InputStreamReader(sk.getInputStream()) - 下面是字符流输出方式和接受方式
Socket sk= new Socket("127.0.0.1",1200);
//利用BufferedWriter类
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(sk.getOutputStream()));
//利用BufferedReader类
BufferedReader br=new BufferedReader(new InputStreamReader(sk.getInputStream())); -
以字符流为例传输和接收过程,切记字符流不能完好传输图片、视频之类的数据 Socket sk= new Socket("127.0.0.1",1200);
String str="你好";
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(sk.getOutputStream()));
bw.write(str); //字符流方式将字符串通过网络写给对方
bw.newLine(); //写后换行
bw.flush(); //表示刷新,也就是立即写给对方
//-----------------------------------------------------------------------------------//
BufferedReader br=new BufferedReader(new InputStreamReader(sk.getInputStream()));
String read = br.readLine(); //字符流方式将对方的信息一行一行的接收过来
//备注:write和read在计算机中实质上其实就是用于写入和读取应用的信息
//例如写入和读取本地记事本,
//而只要远程连接,那么别人的应用也是你的应用,
//因此在聊天软件中,服务端是一个应用,客户端也是一个应用,他们的交流方式固然也是write和read
1.3.完整功能实现
- TCP协议先启动服务端程序,目的是打开端口,再启动客户端,否则出错
- Java程序中TCP协议第一次握手和第二次握手在启动程序时就实现
- 第三次握手是在客户端给服务端发送第一条信息来完成
- 断开连接时应先关闭客户端,再关闭服务端,否则也会服务端出错
- 因为在Socket类下,当三次握手实现后就不区分客户端和服务端了,就是两个应用程序在远程交流
- 服务端代码如下:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import javax.swing.*;
public class Server {
//以下是聊天窗口的实现,上一篇文章有说过,不必多说
private JFrame jf;
private JButton jBsend;
private JTextArea jTAcontent;
private JTextField jText;
private JLabel JLcontent;
private Date data;
private JPanel jPanel;
private JScrollPane scroll;
Server() {
jf = new JFrame("服务端");
jBsend = new JButton("发送");
jTAcontent = new JTextArea(13, 40);
jText = new JTextField(12);
scroll = new JScrollPane(jTAcontent, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); //文本区添加竖直滑动条
JLcontent = new JLabel("聊天记录");
jPanel = new JPanel();
}
public void Win() {
Box boxVBox = Box.createVerticalBox(); //这里应用了垂直盒式布局模式排列组件
boxVBox.add(JLcontent);
boxVBox.add(Box.createVerticalStrut(5));
boxVBox.add(scroll);
boxVBox.add(Box.createVerticalStrut(10));
boxVBox.add(jText);
boxVBox.add(Box.createVerticalStrut(10));
boxVBox.add(jBsend);
boxVBox.add(Box.createVerticalStrut(10));
jPanel.add(boxVBox);
jf.add(jPanel);
jf.setSize(600, 400);
jf.setResizable(false);
jf.setLocationRelativeTo(null);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void Connect() throws Exception {
ServerSocket ss = new ServerSocket(1200);
while (true) {
Socket sk = ss.accept();
jBsend.addActionListener(e -> { //按钮响应事件,实现点击按钮发送信息
String str = jText.getText(); //获取文本框的内容
try {
jTAcontent.append("我:" + str + "\n");
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sk.getOutputStream())); //以字符流发送信息
bw.write(str); //将文本框内容发送给对方
bw.newLine(); //发送后换行
bw.flush(); //立即发送
//不用bw.close(),为了可以一直发送信息
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
jText.setText("");
});
new Thread(() -> { //开启线程,这里是为了服务端可同时接收到多个客户端信息
while (true) { //设置死循环,用于随时接受信息
try {
BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream())); //字符流方式接受信息
String read = br.readLine(); //以字符串方式一行一行接受到信息
jTAcontent.append("客户:" + read + "\n"); //将接收的信息写入文本区
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}).start(); //用start开启线程
}
}
public static void main(String[] args) throws Exception {
Server server = new Server();
server.Win();
server.Connect();
}
}
- 客户端代码如下:
import java.io.*;
import java.net.Socket;
import java.util.Date;
import javax.swing.*;
public class Client {
private JFrame jf;
private JButton jBsend;
private JTextArea jTAcontent;
private JTextField jText;
private JLabel JLcontent;
private Date data;
private JPanel jPanel;
JScrollPane scroll;
Client(){
jf=new JFrame("客户端");
jBsend =new JButton("发送");
jTAcontent =new JTextArea(13,40);
jText =new JTextField(12);
scroll=new JScrollPane(jTAcontent,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); //文本区添加竖直滑动条
JLcontent=new JLabel("聊天记录");
jPanel=new JPanel();
}
public void Win()
{
Box boxVBox=Box.createVerticalBox();
boxVBox.add(JLcontent);
boxVBox.add(Box.createVerticalStrut(5));
boxVBox.add(scroll);
boxVBox.add(Box.createVerticalStrut(10));
boxVBox.add(jText);
boxVBox.add(Box.createVerticalStrut(10));
boxVBox.add(jBsend);
boxVBox.add(Box.createVerticalStrut(10));
jPanel.add(boxVBox);
jf.add(jPanel);
jf.setSize(600, 400);
jf.setResizable(false);
jf.setLocationRelativeTo(null);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void Connect() throws Exception{
Socket sk= new Socket("127.0.0.1",1200);
jBsend.addActionListener(e->{ //Lambda表达式实现点击按钮发送信息
String str=jText.getText(); //获取文本框内容
if (str.matches("\\s+") || str.equals("")) {
JOptionPane.showMessageDialog(jf, "不可发送空白内容");
return;
}
try {
jTAcontent.append("我:"+str+"\n"); //文本区添加文本框内容
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(sk.getOutputStream())); //字符流发送信息
bw.write(str); //发送文本框的信息给对方
bw.newLine(); //发送后换行
bw.flush(); //立即发送
//不用bw.close(),为了可以一直发送信息
jText.setText("");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
new Thread(()->{ //Lambda表达式创建线程
while(true){ //死循环随时接受信息
try {
BufferedReader br=new BufferedReader(new InputStreamReader(sk.getInputStream())); //以字符流接受信息
String read = br.readLine(); //一行一行接受信息
jTAcontent.append("客服:"+read+"\n");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}).start(); //开启线程
});
}
public static void main(String[] args) throws Exception {
Client client=new Client();
client.Win();
client.Connect();
}
}
- ?视频演示如下,这里我服务端和客户端是同一台电脑:
?2.总结
- TCP协议执行三次握手,Java中第三次握手在客户端发送第一条信息实现
- Socket类和ServerSocket类实现连接
- 三次连接后不区分服务端和客户端,相当于两个应用程序远程交流
- TCP原始以字节流传输信息,可改成字符流,字节流可传输大型数据,字符流不可
- 注意服务端和客户端的开启顺序和关闭顺序
|