您的位置:首页 > 理论基础 > 计算机网络

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

2016-03-24 16:48 375 查看
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();
}
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: