使用java socket理解tcp协议
来源:互联网 发布:mac maven .m2文件夹 编辑:程序博客网 时间:2024/06/01 19:20
之前学习tcp协议,都是通过一些理论、图例,看不到摸不着,感觉很抽象、很遥远。现在使用java socket来实现tcp通信,并通过RawCap结合wireshark,来实操一次,用看得见的方式理解tcp协议。tcp只是协议,是概念。java socket是对tcp协议的实现。可以理解为接口和实现类直接的关系。代码中使用到了log4j来打印日志,如何使用自行百度。
服务器端实现如下:
package com.cfysu.socket;import org.apache.log4j.Logger;import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.Executor;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * Created by cj on 17-6-25. */public class SocketServer { private static final Logger LOGGER = Logger.getLogger(SocketClient.class); public static void main(String[] args){ try { new SocketServer().startServer(); }catch (Exception e){ e.printStackTrace(); } } public void startServer() throws IOException { final ServerSocket serverSocket = new ServerSocket(8888); LOGGER.info(Thread.currentThread().getName() + ":服务器端已启动,正在监听..."); ExecutorService pool = Executors.newFixedThreadPool(2); while (true){ //一直监听 //阻塞等待新connection Socket socket = serverSocket.accept(); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())); //final PrintStream printStream = new PrintStream(socket.getOutputStream()); //启动新线程处理客户端请求 pool.submit(new Worker(reader, writer)); } } private class Worker implements Runnable{ private PrintWriter writer; private BufferedReader reader; public Worker(BufferedReader reader, PrintWriter writer){ this.writer = writer; this.reader = reader; } @Override public void run() { LOGGER.info("启动新线程处理客户端请求,threadId:" + Thread.currentThread().getName()); while (true){ //for(int i = 0;i < 5;i++){ String clientMsg = null; try { clientMsg = reader.readLine(); } catch (IOException e) { LOGGER.error("客户端退出", e); } if(null == clientMsg){ LOGGER.info(Thread.currentThread().getName() + ":服务器端收消息线程退出"); return; } LOGGER.info(Thread.currentThread().getName() + ":服务器端接受到了消息===>>>" + clientMsg); //} //响应客户端 writer.write("a msg from server:" + clientMsg); //如果不加换行符,则readline()一直阻塞 writer.write(System.getProperty("line.separator")); //writer.println("a msg from server:" + clientMsg); writer.flush(); LOGGER.info(Thread.currentThread().getName() + ":已回复客户端消息"); } } }}
客户端实现如下:
package com.cfysu.socket;import org.apache.log4j.Logger;import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.Scanner;import java.util.concurrent.Callable;import java.util.concurrent.Future;import java.util.concurrent.FutureTask;/** * Created by cj on 17-6-25. */public class SocketClient { private static final Logger LOGGER = Logger.getLogger(SocketClient.class); public static void main(String[] args){ try { new SocketClient().startClient(); } catch (IOException e) { LOGGER.error("IO异常", e); } } public void startClient() throws IOException { Socket socket = new Socket("127.0.0.1", 8888); PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); //启动线程接收消息 new Thread(new FutureTask<String>(new Receiver(reader))).start(); //主线程,用户发送消息 Scanner scanner = new Scanner(System.in); while (true){ String userMsg = scanner.next(); if("bye".equals(userMsg)){ LOGGER.info(Thread.currentThread().getName() + ":bye bye"); break; } writer.println(userMsg); writer.flush(); LOGGER.info(Thread.currentThread().getName() + ":用户信息已发出"); } LOGGER.info(Thread.currentThread().getName() + ":主线程退出"); } private class Receiver implements Callable<String>{ private BufferedReader reader; public Receiver(BufferedReader reader){ this.reader = reader; } @Override public String call() { int msgCount = 0; while (true){ //Thread.sleep(10000); //msgCount++; //printWriter.println("---thread msg---" + msgCount); //printWriter.flush(); LOGGER.info(Thread.currentThread().getName() + ":等待服务器回复消息"); String receiveMsg = null; try { receiveMsg = reader.readLine(); } catch (IOException e) { LOGGER.error("服务器端退出", e); } if(null == receiveMsg){ LOGGER.info(Thread.currentThread().getName() + ":客户端收消息线程退出"); return "exit"; } LOGGER.info(Thread.currentThread().getName() + ":收到新消息===>>>" + receiveMsg); } } }}
稍微解释下上面的代码。客户端使用主线程读取用户输入,并发送给服务器端。另外起了一个线程用于读取服务器端返回数据。服务器开启一个容量为2的线程池,接受到客户端请求后启动线程响应客户端请求,这里只是简单把客户端数据返回。在启动socket之前,先打开RawCap抓取数据包,如图。
启动ServerSocket、ClientSocket并使用客户端发送文字给服务端。结束后使用WireShark打开抓包生成的数据文件。可以看到前三个数据包为tcp建立连接的三次握手。
结合下图,可以清晰的分析出三次握手的过程。
图片引用自https://www.cnblogs.com/TankXiao/archive/2012/10/10/2711777.html
接着看第四个和第五个包,可以看到客户端发送的消息和服务器端返回的消息。我当时在客户端发送字符串“client”,服务器端返回“a msg from server:client”从图中可以看出。
其中psh表示有数据传输。
RawCap下载链接:
http://www.netresec.com/?page=RawCap
WireShark下载链接:
https://www.wireshark.org/
阅读全文
1 0
- 使用java socket理解tcp协议
- SOCKET简单理解与tcp协议浅析
- 【ios socket 即时通讯】----TCP协议理解
- java使用TCP协议
- Java系列-Socket网络编程,TCP/IP和Http等网络协议理解
- Java Tcp协议socket编程学习
- 【TCP/IP协议】java SOCKET网络编程
- Java Socket编程之TCP协议
- 浅析JAVA SOCKET及TCP/IP协议
- Java Socket编程和TCP/IP协议
- Java Socket编程和TCP/IP协议
- Java -- Tcp Socket的使用
- TCP/IP网络协议的通俗理解,socket,http,soap。
- TCP/IP网络协议的通俗理解,socket,http,soap。
- TCP/IP网络协议的通俗理解,socket,http,soap。
- TCP与UDP协议socket函数实例理解
- ios TCP协议的理解(基于Socket【套接字】)
- <>socket-通信-tcp协议
- ubuntu boot not enough space
- mybatis的dao中@param注解
- xorm根据数据库表生成对应的结构体
- 虫子爬井(有待改进)
- hbase写的报错
- 使用java socket理解tcp协议
- java版的跳转操作
- 安装TensorFlow后 import tensorflow 报错
- Intellij IDEA 本人快捷键和个人喜好设置笔记
- 构建可重复读取inputStream的request
- Fresco简单应用
- linux练习 十一 信号的阻塞和捕捉
- 使用Springboot配置druid
- 【python 马氏距离】python实现马氏距离算法