一个简单的多客户命令行聊天程序
客户端
package com.sehun.Multi;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class MultiClientTalk {
int num;
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 5285);
System.out.println("Client run!"+"\n");
//键盘输入流,获取用户从键盘输入的信息
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
//输出流,从客户端将信息发送给服务端
PrintWriter out = new PrintWriter(socket.getOutputStream());
//输入流,接收来自网络上服务端发送给本程序的信息
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = sin.readLine();
String readLine = null;
//用户通过“over”字符串来告诉程序是否结束
while(!line.equals("over")){
out.println(line);
//强制输出数据(清空缓冲区的数据流)
out.flush();
readLine = in.readLine();
if (readLine==null){
System.out.println("服务端已下线,请输入【over】结束本次聊天");
}else
System.out.println("Server: "+readLine);
line = sin.readLine();
}
out.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端
package com.sehun.Multi;
import java.io.IOException;
import java.net.ServerSocket;
public class MultiServerTalk {
static int clientNum = 0;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean receiving = true;
try {
serverSocket = new ServerSocket(5285);
System.out.println("Server Run !"+"\n");
} catch (IOException e) {
System.out.println("不能连接到 5285 端口");
System.exit(-1);
}
while (receiving){
new ServerThread(serverSocket.accept(),clientNum).start();
clientNum++;
}
serverSocket.close();
}
}
package com.sehun.Multi;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ServerThread extends Thread{
Socket socket = null;
int clientNum;
public ServerThread(Socket socket,int clientNum){
this.socket = socket;
this.clientNum = clientNum+1;
}
public void run(){
System.out.println("Client"+clientNum+"连接过来了");
try{
//键盘输入流,获取用户从键盘输入的信息
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
//输出流,将服务端的内容发送给客户端
PrintWriter out = new PrintWriter(socket.getOutputStream());
//输入流,读取来自客户端发给它的信息
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String readLine = in.readLine();
System.out.println("Client"+clientNum+" :"+readLine);
String line = sin.readLine();
while (!line.equals("over")){
out.println(line);
out.flush();
readLine = in.readLine();
if (readLine==null){
System.out.println("客户端"+clientNum+"已下线,输入【over】可结束本次聊天");
}else
System.out.println("Client"+clientNum+" :"+readLine);
line = sin.readLine();
}
out.close();
in.close();
socket.close();
}catch(Exception e){
System.out.println("error");
}
}
}
运行结果
一个简单的带界面的双人聊天程序
聊天框
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ChatFrame extends JFrame implements ActionListener {
//文本输入框,用于接收聊天时的输入
JTextField tf;
//用来展示聊天记录
JTextArea ta;
//滚动面板
JScrollPane sp;
//发送
JButton button;
//面板,承载JButton JTextField两个类的对象
JPanel p;
int port;
String s = "";
//聊天界面对应的用户id
String userID;
Date date;
ServerSocket serverSocket;
Socket socket;
//接收输入
BufferedReader in;
//发送输出
PrintWriter out;
String line;
/*
* ID--我自己的ID
* remotelID--对应的和我聊天的远程ID
* isServer--判断是服务端还是客户端
*/
public ChatFrame(String ID,String remotelID,String IP,int port,boolean isServer){
super(ID);
userID = ID;
this.port = port;
ta = new JTextArea();
//设置该文本区域(聊天记录框)不可编辑
ta.setEditable(false);
//将ta放到滚动面板里
sp = new JScrollPane(ta);
//设置窗口大小
this.setSize(330,400);
this.setResizable(false);
try {
//设置显示风格
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch (Exception e) {
e.printStackTrace();
}
//将滚动面板的对象放到整个窗口的中间
this.getContentPane().add(sp,"Center");
p = new JPanel();
this.getContentPane().add(p,"South");
button = new JButton("发送");
//文本输入区域,宽度为20个字符
tf = new JTextField(20);
//将输入光标放在JTextField对象tf上
tf.requestFocus();
//将tf和button都放到面板中
p.add(tf);
p.add(button);
//设置窗口可退出
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
//窗口可显示
this.setVisible(true);
//注册监听器,处理这些事件的对象为this--当前对象
button.addActionListener(this);
tf.addActionListener(this);
if (isServer){
try{
serverSocket = null;
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
System.out.println("不能连接到客户端");
}
socket = null;
try {
socket = serverSocket.accept();
} catch (IOException e) {
e.printStackTrace();
}
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream());
}catch (Exception e){
System.out.println(e);
}
}else{
try {
socket = new Socket(IP,port);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream());
} catch (Exception e) {
System.out.println(e);
}
}
while (true){
try{
//获得输入
line = in.readLine();
//获得信息的时间
date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String cuurrentTime = format.format(date);
s+=remotelID+"---"+cuurrentTime+":\n"+line+"\n";
//加到聊天记录框里
ta.setText(s);
}catch (Exception e){
e.printStackTrace();
}
}
}
//处理本地信息,文本框输入的信息
@Override
public void actionPerformed(ActionEvent e) {
date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String cuurrentTime = format.format(date);
s+=userID+"---"+cuurrentTime+":\n"+tf.getText()+"\n";
//将输入框的内容加到聊天记录框
ta.setText(s);
//将输入框的内容输出
out.println(tf.getText());
out.flush();
//清空输入框
tf.setText("");
//获得焦点
tf.requestFocus();
}
}
启动
//服务端
public class ServerFrame {
public static void main(String[] args) {
ChatFrame cserver = new ChatFrame("巴西龟", "百香果", "127.0.0.1", 2026, true);
}
}
//客户端
public class ClientFrame {
public static void main(String[] args) {
new ChatFrame("百香果", "巴西龟", "127.0.0.1", 2026, false);
}
}
运行结果
数据报通信
UDP协议
- User Datagram Protocol 用户数据报协议
- 非面向连接的提供不可靠的数据包式的数据传输协议。
- 基于UDP协议进行网络通讯的类:DatagramPacket,DatagramSocket,MulticastSocket等
TCP协议
- 面向连接的能够提供可靠的流式数据传输的协议
- 基于TCP协议进行网络通讯的类:URL,URLConnection,Socket,ServerSocket
代码实现
- DatagramSocket(int port)
- DatagramPacket(byte[] buf,int length)----接收
- DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)----发送
接收数据报
DatagramPacket packet = new DatagramPacket(buf,256);
socket.receive(packet);
发送数据报
DatagramPacket packet = new DatagramPacket(buf,buf.length,address,port);
socket.send(packet);