[疯狂Java]TCP:协议字符、记录客户端信息

本文介绍了一种基于TCP协议的通信机制实现方式,包括客户端和服务端的交互流程、自定义协议字符的意义及其应用示例。通过定义特定的协议字符,客户端能够发送登录请求、群聊消息及私聊请求等,服务器则能进行相应的处理并反馈结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 这里用一个示例介绍TCP通信常用的技术:

    1) 一般需要自定义双方之间通信的规则,比如用某个标志来代表你是红钻、黄钻还是想私聊或者群聊之类的;

    2) 这类规则就得在数据包中用协议字符来表示,协议字符是自定义的,是通信双方交流的约定;

    3) 而通常服务器需要记录客户端的信息,比如登录信息之类的,这就需要在客户端发送请求的时候将这些信息都一并发送,服务器端可以抽取并保存起来;


2. 示例:

协议字符:

package com.lirx;

public interface Protocol {
	int PROTOCOL_LEN = 2; // 协议字符的长度
	
	// 客户端向服务器端的通信协议标志
	String MSG_ROUND = "§γ"; // 聊天内容包裹标志
	String USER_ROUND = "∏∑"; // 用户名包裹标志
	String PRIVATE_ROUND = "★【"; // 私聊请求包裹标志
	String SPLIT_SIGN = "※"; // 分隔符
	
	// 服务器端响应标志(表示登录状态)
	String LOGIN_SUCCESS = "1"; // 登录成功
	String NAME_REP = "-1"; // 重复登录
}
服务器端:

package com.lirx.server;

import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

import com.lirx.map.MyMap;

public class Server {
	private static final int SERVER_PORT = 30000;
	
	private MyMap<String, PrintStream> clientsPsMap = new MyMap<>();
	
	public void init() {
		try (ServerSocket ss = new ServerSocket(SERVER_PORT)) {
			while (true) {
				Socket s = ss.accept();
				new ServerThread(s, clientsPsMap).start();
			}
		}
		catch (IOException e) {
			System.out.println("服务器启动失败!是否端口" + SERVER_PORT + "被占用?");
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Server().init();
	}

}
package com.lirx.server;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

import com.lirx.Protocol;
import com.lirx.map.MyMap;

public class ServerThread extends Thread {
	private Socket s;
	private MyMap<String, PrintStream> map;
	
	public ServerThread(Socket s, MyMap<String, PrintStream> map) {
		this.s = s;
		this.map = map;
	}

	private String getContent(String line) { // 脱去信息中的协议符号
		return line.substring(Protocol.PROTOCOL_LEN,
				line.length() - Protocol.PROTOCOL_LEN);
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		// super.run();
		
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			PrintStream ps = new PrintStream(s.getOutputStream());
			
			String line = "";
			while ((line = br.readLine()) != null) {
				if (line.startsWith(Protocol.USER_ROUND) && // 用户登录
					line.endsWith(Protocol.USER_ROUND)) {
					String userName = getContent(line);
					if (map.containsKey(userName)) {
						System.out.println(userName + "重复登录");
						ps.println(Protocol.NAME_REP);
					}
					else {
						System.out.println(userName + "登陆成功");
						ps.println(Protocol.LOGIN_SUCCESS);
						map.put(userName, ps);
					}
				}
				else if (line.startsWith(Protocol.PRIVATE_ROUND) &&
						 line.endsWith(Protocol.PRIVATE_ROUND)) { // 私聊请求
					String tarAndMsg = getContent(line);
					String[] split = tarAndMsg.split(Protocol.SPLIT_SIGN);
					String tar = split[0];
					String msg = split[1];
					map.get(tar).println(map.getKeyByValue(ps) + "悄悄对你说:" + msg);
				}
				else { // 群聊请求
					String msg = getContent(line);
					for (PrintStream eachPs: map.valueSet()) {
						eachPs.println(map.getKeyByValue(ps) + "说:" + msg);
					}
				}
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}
客户端:

package com.lirx.client;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

import javax.swing.JOptionPane;

import com.lirx.Protocol;

public class Client {

	private final static int SERVER_PORT = 30000;

	private Socket s;
	private PrintStream ps;
	private BufferedReader br;
	private BufferedReader keyIn;

	public void init() {
		try {
			s = new Socket("127.0.0.1", SERVER_PORT);
			ps = new PrintStream(s.getOutputStream());
			br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			keyIn = new BufferedReader(new InputStreamReader(System.in));

			String tip = "";
			while (true) { // 反复弹出提示框要求输入用户名登录
				String name = JOptionPane.showInputDialog(tip + "输入用户名");
				ps.println(Protocol.USER_ROUND + name + Protocol.USER_ROUND);
				String res = br.readLine();
				if (res.equals(Protocol.NAME_REP)) {
					tip = "重复登录";
					continue;
				}
				if (res.equals(Protocol.LOGIN_SUCCESS)) {
					break;
				}
				tip = "";
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		new ClientThread(br).start(); // 已登录成功就立马运行接受服务器消息的线程,随时接受群聊和私聊信息

		try { // 主线程的任务是接受键盘输入并发送给服务器
			String line = "";
			while ((line = keyIn.readLine()) != null) {
				if (line.indexOf(":") > 0 && line.startsWith("//")) { // 发起私聊:格式是"//XXX:内容"
					line = line.substring(2);
					String[] split = line.split(":");
					ps.println(Protocol.PRIVATE_ROUND + split[0] + Protocol.SPLIT_SIGN + split[1]
							+ Protocol.PRIVATE_ROUND);
				} else { // 发起群聊
					ps.println(Protocol.MSG_ROUND + line + Protocol.MSG_ROUND);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		new Client().init();
	}
}
package com.lirx.client;

import java.io.BufferedReader;
import java.io.IOException;

public class ClientThread extends Thread { // 接受服务器的私聊和群聊的消息并显示在控制台上
	private BufferedReader br;
	
	public ClientThread(BufferedReader br) {
		this.br = br;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		// super.run();
		String line = "";
		try {
			while ((line = br.readLine()) != null) {
				System.out.println(line);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally { // 线程租后结束时关闭资源
			if (br != null)
				try {
					br.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}
	
	
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值