[疯狂Java]TCP:协议字符、记录客户端信息
2016-03-24 16:48
375 查看
1. 这里用一个示例介绍TCP通信常用的技术:
1) 一般需要自定义双方之间通信的规则,比如用某个标志来代表你是红钻、黄钻还是想私聊或者群聊之类的;
2) 这类规则就得在数据包中用协议字符来表示,协议字符是自定义的,是通信双方交流的约定;
3) 而通常服务器需要记录客户端的信息,比如登录信息之类的,这就需要在客户端发送请求的时候将这些信息都一并发送,服务器端可以抽取并保存起来;
2. 示例:
协议字符:
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(); } } } }
相关文章推荐
- HttpWebRequest 下载html
- https://github.com/akullpp/awesome-java
- Struts2当调用action时出现HTTP Status 404 问题解决
- C++文件操作详解http://www.cnblogs.com/likebeta/archive/2012/06/16/2551662.html
- HttpClient,HttpGet
- 网络状态检测
- 卷积神经网络全面解析
- HTTPS学习笔记
- [题目转自http://www.33iq.com/]趣味数学题1 王师傅亏了多少?
- 叶脊网络拓扑(leaf-spine)
- iOS 网络请求 NSURLSession
- 网络爬虫-pyspider环境搭建(standalone)
- 判断iOS应用是否开放HTTP权限的方法
- 网络访问使用说明
- tcpdump#0入门
- IOS 网络-深入浅出(一 )-> 三方SDWebImage
- apache https配置步骤
- CentOS6.6修改主机名和网络信息
- TCP与UDP的区别
- T-SQL XQuery (XML路径查询) (转)http://blog.csdn.net/Beirut/article/details/8150116