利用TCP实现简单聊天程序

来源:互联网 发布:h3c交换机禁止mac 编辑:程序博客网 时间:2024/05/21 15:40

TCP通信的特点是面向连接,即通信双方必须先建立连接然后才能进行通信,安全性比较高,保证信息的正确性。

先介绍客户端怎么连接服务器端:

服务器打开某个端口并进行监听,等待客户端连接;客户端根据服务器的IP地址,连接服务器的某个端口。服务器端用ServerSocket(port)打开port端口并监听,客户端用Socket(IP,port)连接服务器端的port端口。在服务器端用accept函数来接受客服端的socket对象。accept函数是一个死等函数,如果没有客户端连接,程序将会在这里阻塞知道有客户端连接。

服务器端:

package Easy;import java.net.ServerSocket;import java.net.Socket;
public class Server {private int Port = 9999;private ServerSocket SS;private Socket socket;public Server(){try{SS = new ServerSocket(Port);socket = SS.accept();String ipAddress = socket.getInetAddress().getHostAddress();
System.out.println("客户端" + ipAddress + "连接");}catch(Exception ex){}}public static void main(String[] args){new Server();}}

客户端:

package Easy;import java.net.InetAddress;import java.net.Socket;public class Client {public static void main(String[] args) throws Exception{InetAddress ip = InetAddress.getByName("Localhost");int Port = 9999;Socket socket = new Socket(ip,Port);}}

先打开服务器端,此时服务器端监听9999号端口;然后打开客户端,这时候服务器端将输出客户端的IP地址。

如何实现客户端与服务器端的相互通信?(单)

要知道怎么实现相互通信,首先得知道怎么发送数据和接收数据。

发送字符串数据:

OutputStream os = socket.getOutputStream();

PrintStream ps = new PrintStream(os);

ps.println("content");

接收字符串数据:

InputStream is = socket.getInputStream();

BufferedReader br = new BufferedReader(new InputStreamReader(is));

String str = br.readLine();

readLine函数也是一个死等函数,如果客户端连接上了,但是没有发送信息,就会造成阻塞。所以最好的解决方法是将读取信息的代码写在线程内。

知道了怎么发送、接收数据之后,服务器端先打开端口并监听,假如有客户端连接则开启线程,重写run()方法。相互通信时并不知道对方什么时候发送信息,所以就需要线程来实现自动接收信息的功能,然后需要一个发送信息的函数,在这里我选择button按钮的点击事件来实现,发送消息时直接在输入框回车就可以了。

服务器端:

package Alone;import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintStream;import java.net.ServerSocket;import java.net.Socket;import javax.swing.JFrame;import javax.swing.JTextArea;import javax.swing.JTextField;public class AServer extends JFrame implements ActionListener,Runnable {private int Port = 9999;private ServerSocket SS;private Socket socket;private JTextArea area = new JTextArea("聊天内容:"+'\n');private JTextField field = new JTextField("");public AServer(){this.setTitle("服务器");this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.add(area,BorderLayout.CENTER);this.add(field,BorderLayout.NORTH);field.addActionListener(this);this.setSize(190, 200);this.setVisible(true);try{SS = new ServerSocket(Port);socket = SS.accept();new Thread(this).start();}catch(Exception ex){}}public void run(){try{while(true){InputStream is = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is));String str = br.readLine();area.append(str + '\n');}}catch(Exception ex){}}public void actionPerformed(ActionEvent e){try{OutputStream os = socket.getOutputStream();PrintStream ps = new PrintStream(os);ps.println("服务器说:" + field.getText());field.setText("");}catch(Exception ex){}}public static void main(String[] args){new AServer();}}

客户端:

package Alone;import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintStream;import java.net.InetAddress;import java.net.Socket;import javax.swing.JFrame;import javax.swing.JTextArea;import javax.swing.JTextField;public class AClient extends JFrame implements ActionListener, Runnable {private Socket socket;private int Port = 9999;private InetAddress ip;private JTextArea area = new JTextArea("聊天内容:\n");private JTextField field = new JTextField("");public AClient(){this.setTitle("客户端");this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.add(field,BorderLayout.NORTH);field.addActionListener(this);this.add(area, BorderLayout.CENTER);this.setSize(190, 200);this.setVisible(true);try{ip = InetAddress.getByName("Localhost");socket = new Socket(ip,Port);OutputStream os = socket.getOutputStream();PrintStream ps = new PrintStream(os);ps.println("客户端连接");new Thread(this).start();}catch (Exception ex){}}public void run(){try{while(true){InputStream is = socket.getInputStream();BufferedReader bf = new BufferedReader(new InputStreamReader(is));String str = bf.readLine();area.append(str + '\n');}}catch (Exception ex){}}public void actionPerformed(ActionEvent e){try{OutputStream os = socket.getOutputStream();PrintStream ps = new PrintStream(os);ps.println("客户端说:" + field.getText());field.setText("");}catch (Exception ex){}}public static void main(String[] args) {new AClient();}}
实验过程:

                   

                   

多客户聊天(多)

在实际的应用中,聊天程序是客户端与客户端聊天,而不是客户端与服务器端聊天。要是现这个功能,服务器端就要起到一个转发的作用。
服务器端不知道客户端什么时候连接,所以就需要一个线程专门负责多个客户端连接;当客户端连接上之后,不知道什么时候会发送消息,所以需要单独为这个客户端开一个线程来不停的读取它发送过来的消息,在程序代码中用ArrayList动态数组来保存每个每一个客户端的线程;服务器端接收到某个客户端发送的消息,需要将消息转发给其他客户端,这就需要服务器端保存各个客户端的输入输出流的引用。
由于是多客户聊天,需要一个name来区别每个客户端。客户端没多大变化,同样在run()函数中编写接收消息的代码,用按钮点击事件来发送消息。
服务器端:
package Group;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintStream;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;public class GServer implements Runnable {private int Port = 9999;private ServerSocket SS;private Socket socket;private ArrayList clients = new ArrayList();  //保存客户端线程public GServer(){try{SS = new ServerSocket(Port);new Thread(this).start();}catch(Exception ex){}}public void run(){try{while(true){socket = SS.accept();ChatThread ct = new ChatThread(socket);clients.add(ct);ct.start();}}catch(Exception ex){}}class ChatThread extends Thread{private Socket s;private InputStream is;private OutputStream os;private BufferedReader br;private PrintStream ps;public ChatThread(Socket socket) throws Exception{this.s = socket;is = this.s.getInputStream();os = this.s.getOutputStream(); br = new BufferedReader(new InputStreamReader(is));ps = new PrintStream(os);}public void run(){try{while(true){String str = br.readLine();sendMessage(str);}}catch (Exception ex){}}public void sendMessage(String str){for(int i=0; i<clients.size(); i++){ChatThread ct = (ChatThread)clients.get(i);ct.ps.println(str);}}}public static void main(String[] args){new GServer();}}
客户端:
package Group;import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintStream;import java.net.InetAddress;import java.net.Socket;import javax.swing.JFrame;import javax.swing.JOptionPane;import javax.swing.JTextArea;import javax.swing.JTextField;public class GClient extends JFrame implements ActionListener, Runnable {private Socket socket;private int Port = 9999;private InetAddress ip;private String name;private JTextArea area = new JTextArea("以下是聊天内容:\n");private JTextField field = new JTextField("");public GClient(){this.setTitle("客户端");this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.add(field,BorderLayout.NORTH);field.addActionListener(this);this.add(area, BorderLayout.CENTER);this.setSize(240, 260);this.setVisible(true);name = JOptionPane.showInputDialog("输入昵称:");try{ip = InetAddress.getByName("Localhost");socket = new Socket(ip,Port);JOptionPane.showMessageDialog(this, "连接成功");this.setTitle("客户端:" + name);new Thread(this).start();}catch (Exception ex){}}public void run(){try{while(true){InputStream is = socket.getInputStream();BufferedReader bf = new BufferedReader(new InputStreamReader(is));String str = bf.readLine();area.append(str + '\n');}}catch (Exception ex){}}public void actionPerformed(ActionEvent e){try{OutputStream os = socket.getOutputStream();PrintStream ps = new PrintStream(os);ps.println(name + "说:" + field.getText());field.setText("");}catch (Exception ex){}}public static void main(String[] args) {new GClient();}}
实验过程:
                                   
首先打开服务器端,然后打开客户端输入客户端name,分别是Dkangel、Lisi、Zhangsan,然后在各自的输入框内输入信息,回车即可发送消息。

以上就是我所要介绍的TCP实现简单聊天程序。

不久前还写了UDP实现简单聊天程序。


0 0