IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> java 手撸TCP协议栈 (2) 完成一个简单的http静态服务器 -> 正文阅读

[网络协议]java 手撸TCP协议栈 (2) 完成一个简单的http静态服务器

在此警告,协议栈代码具有一定危险性,只用于测试,运行于测试环境如虚拟机环境、内网测试环境。切勿用于真实环境或生产环境,如因此造成严重的后果本人一概不负责。

java 手撸TCP协议栈 (1) 调用pcap ? 完成了操作网卡的api,这是实现tcp协议栈的最重要的基础部分,有了这个基础,就可以飞起来了。

在这里继续介绍在(1)的基础上完整的实现一个简单的静态http服务器。

要完成一个http服务器,首先需要了解底层的协议是什么样子的,这里不贴协议格式了,csdn一搜一大把,各位自己倒杯茶慢慢搜慢慢看。

下面直接贴代码:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;


public class HttpServerPCap {
	
	static class SocketStruct{
		public byte[] remoteMacAddr;
		public byte[] remoteAddr;
		public int remotePort;
		public long identifyId;
		public long seqenceId ;
		public long acknowlegeId;
		public ByteBuffer buffer;
		public int status; // 1 received syn 2 estable 3 fin1 4 fin2
	}
	
	private static byte[] localMacAddr = {(byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06};
	private static byte[] localIp = {(byte)192, (byte)168, (byte)56, (byte)113};
	private static int localPort = 8080;
	
	private static Map<String, SocketStruct> socketStructMap = new ConcurrentHashMap<String, SocketStruct>();
	
	private static Random random = new Random();
	
	private static final int TcpDataMaxLen = 1460;

	public static void main(String[] args) {		

		NativeMapping.PcapErrbuf errbuf = new NativeMapping.PcapErrbuf();
		Pointer handle = NativeMapping.pcap_open_live("\\Device\\NPF_{C8E924E8-3C99-411D-8A9B-5A13CCC5E393}", 65536, 1, 1000, errbuf);
		if (handle == null) {
			System.out.println("Open device failed");
			System.exit(-1);
		}
		NativeMapping.bpf_program prog = new NativeMapping.bpf_program();
		String filterStr = String.format("ether dst %02X:%02X:%02X:%02X:%02X:%02X", 
				localMacAddr[0], localMacAddr[1], localMacAddr[2], localMacAddr[3], localMacAddr[4], localMacAddr[5]);
		int rc = NativeMapping.pcap_compile(handle, prog, filterStr, 1, -1);
		NativeMapping.pcap_freecode(prog);
		
		long timeStart = System.currentTimeMillis();
		while (true) {
			receiveTcpData(handle);
			for(String key : socketStructMap.keySet()){
				SocketStruct s = socketStructMap.get(key);
				if(s.status==2){
					if(s.buffer!=null 
							&& s.buffer.position()==s.buffer.limit() 
							&& s.buffer.position()<s.buffer.capacity()){
						int size = TcpDataMaxLen;
						if(s.buffer.capacity()-s.buffer.position()<size){
							size = s.buffer.capacity()-s.buffer.limit();
						}
						sendTcpReply(handle, s.remoteMacAddr, s.remoteAddr, s.remotePort,
								s.identifyId, s.seqenceId, s.acknowlegeId,
								false, false, false, false, true, true, false, false, false,
								s.buffer.array(), 0, size);
						s.buffer.limit(s.buffer.limit()+size);
					}
				}
			}
		}

	}

	private static int receiveTcpData(Pointer handle) {
		int rc;
		PointerByReference headerPP = new PointerByReference();
		PointerByReference dataPP = new PointerByReference();
		rc = NativeMapping.pcap_next_ex(handle, headerPP, dataPP);
		switch (rc) {
		case 0:
			// timeout
			break;
		case 1:
			Pointer headerP = headerPP.getValue();
			Pointer dataP = dataPP.getValue();
			if (headerP == null || dataP == null) {
			} else {
			

				final int len = NativeMapping.pcap_pkthdr.getLen(headerP);
				final byte[] buff = dataP.getByteArray(0, NativeMapping.pcap_pkthdr.getCaplen(headerP));
				
				if (buff[12] == 8 && buff[13] == 6 && buff[14] == 0 && buff[15] == 1 && buff[16] == 8 && buff[17] == 0 && buff[20] == 0
						&& buff[21] == 1) {
					// proc arp request and reply arp reply package
					byte[] arpBuff = new byte[42];
					System.arraycopy(buff, 6, arpBuff, 0, 6); // dest mac
					System.arraycopy(localMacAddr, 0, arpBuff, 6, 6); // src mac
					arpBuff[12] = 8; arpBuff[13] = 6;
					arpBuff[14] = 0; arpBuff[15] = 1;
					arpBuff[16] = 8; arpBuff[17] = 0; // ipv 4
					arpBuff[18] = 6;  // hw size
					arpBuff[19] = 4;  // protocol size
					arpBuff[20] = 0; arpBuff[21] = 2; // arp reply
					System.arraycopy(localMacAddr, 0, arpBuff, 22, 6); // sender mac
					System.arraycopy(localIp, 0, arpBuff, 28, 4); // sender ip
					System.arraycopy(buff, 22, arpBuff, 32, 6); // target mac
					System.arraycopy(buff, 28, arpBuff, 38, 4); // target ip
					NativeMapping.pcap_sendpacket(handle, arpBuff, arpBuff.length);
					
				}else if(buff[12] == 8 && buff[13] == 0 && buff[14] == (byte)0x45 && buff[15] == 0 && buff[23]==6 ){
					if(calcBuffChecksum(buff, 14, 20)==0){
						int ipTotalLen = ((buff[16]&0xff)<<8)+(buff[17]&0xff);
						int checkSum = calcBuff16BitsSum(buff, 26, 8);
						checkSum += 6+(ipTotalLen-20)+calcBuff16BitsSum(buff, 14+20, ipTotalLen-20);
						checkSum = (~(((checkSum>>16)&0xffff)+(checkSum&0xffff)))&0xffff;
						if(checkSum==0){
							if( buff[30]==localIp[0] && buff[31]==localIp[1] && buff[32]==localIp[2] && buff[33]==localIp[3] ){
								int tcpHdrLen = (buff[46]&0xff)>>2;
								int tcpFlags = ((buff[46]&0x1)<<8)+(buff[47]&0xff);
								int srcPort = ((buff[34]&0xff)<<8)+(buff[35]&0xff);
								int destPort = ((buff[36]&0xff)<<8)+(buff[37]&0xff);
								String mapId = String.format("%d.%d.%d.%d %d - %d.%d.%d.%d %d", 
										buff[36]&0xff,buff[37]&0xff,buff[38]&0xff,buff[39]&0xff, destPort,
										buff[26]&0xff,buff[27]&0xff,buff[28]&0xff,buff[29]&0xff, srcPort
										);
								SocketStruct s = socketStructMap.get(mapId);
								long tempAcknoledgeId = ((long)(buff[38]&0xff)<<24) + ((buff[39]&0xff)<<16) + ((buff[40]&0xff)<<8) + (buff[41]&0xff);
								if(tcpFlags==2){
									if(s==null){
										s = new SocketStruct();
										s.remoteMacAddr = new byte[6];
										System.arraycopy(buff, 6, s.remoteMacAddr, 0, 6);
										s.remoteAddr = new byte[4];
										System.arraycopy(buff, 26, s.remoteAddr, 0, 4);
										s.remotePort = ((buff[34]&0xff)<<8)+(buff[35]&0xff);
										s.identifyId = random.nextInt(1800)+6000;
										s.seqenceId = random.nextInt(1000)+2000;
										s.acknowlegeId = ((long)(buff[38]&0xff)<<24) + ((buff[39]&0xff)<<16) + ((buff[40]&0xff)<<8) + (buff[41]&0xff);
										socketStructMap.put(mapId, s);
									}
									sendTcpReply(handle, s.remoteMacAddr, s.remoteAddr, s.remotePort,
											s.identifyId, s.seqenceId, ++s.acknowlegeId,
											false, false, false, false, true, false, false, true, false,
											null, -1, 0 );
									s.identifyId+=2;
									s.status = 1;
								} else if((tcpFlags&0x1fe)==0x10){
									if(s!=null){
										s.identifyId+=2;
										s.acknowlegeId = ((long)(buff[38]&0xff)<<24) + ((buff[39]&0xff)<<16) + ((buff[40]&0xff)<<8) + (buff[41]&0xff);
										if(s.status==1){
											s.seqenceId++;
											s.status = 2;
										}else if(s.status==2){
											if(s.buffer!=null){
												s.seqenceId += s.buffer.limit()-s.buffer.position();
												s.buffer.position(s.buffer.limit());
												if(s.buffer.position()==s.buffer.capacity()){
													sendTcpReply(handle, s.remoteMacAddr, s.remoteAddr, s.remotePort,
															s.identifyId, s.seqenceId, s.acknowlegeId,
															false, false, false, false, true, false, false, false, true,
															null, -1, 0 );
													s.status = 3;
												}
											}
										}else if(s.status==3){
											sendTcpReply(handle, s.remoteMacAddr, s.remoteAddr, s.remotePort,
													s.identifyId, s.seqenceId, s.acknowlegeId,
													false, false, false, false, true, false, false, false, true,
													null, -1, 0 );
											s.status=4;
										}else if(s.status==4){
											socketStructMap.remove(mapId);
										}
									}
								} else if((tcpFlags&0x1fe)==0x18){
									if(s!=null && s.buffer==null){
										if(tempAcknoledgeId==s.acknowlegeId){
											s.acknowlegeId += ipTotalLen-20-tcpHdrLen;
											sendTcpReply(handle, s.remoteMacAddr, s.remoteAddr, s.remotePort,
													s.identifyId, s.seqenceId, s.acknowlegeId,
													false, false, false, false, true, false, false, false, false,
													null, -1, 0 );
											procHttpRequestData(s, new String(buff, 14+20+tcpHdrLen, ipTotalLen-20-tcpHdrLen));
										}
									}
								}
								if((tcpFlags&1)>0){
									if(s!=null){
										if(s.status==2 || s.status==3){
											sendTcpReply(handle, s.remoteMacAddr, s.remoteAddr, s.remotePort,
													s.identifyId, s.seqenceId, ++s.acknowlegeId,
													false, false, false, false, true, false, false, false, false,
													null, -1, 0 );
											//s.identifyId+=2;
											if(s.status==2){
												s.status=3;
												sendTcpReply(handle, s.remoteMacAddr, s.remoteAddr, s.remotePort,
														s.identifyId, s.seqenceId, s.acknowlegeId,
														false, false, false, false, true, false, false, false, true,
														null, -1, 0 );
											}else if(s.status==3){
												s.status=4;
												socketStructMap.remove(mapId);
											}
										}
									}
								}
							}
						}
					}
				}
				return len;
				
			}
			break;
		case -1:
			break;
		case -2:
			break;
		default:
			break;
		}
		return 0;
	}
	
	private static void readFileData(File f, ByteBuffer bf) throws Exception{
		byte[] buff = new byte[1024];
		FileInputStream in = new FileInputStream(f);
		while(in.available()>0){
			int size = in.read(buff);
			bf.put(buff, 0, size);
		}
		in.close();
		
	}
	
	private static int procHttpRequestData(SocketStruct s, String content){
		int pos = content.indexOf("\r\n\r\n");
		if(pos<0){
			pos = content.indexOf("\n\n");
			if(pos<0){
				pos = content.lastIndexOf("\r\n");
				if(pos<0){
					pos = content.length();
				}else{
					pos += 2;
				}
			}else{
				pos += 2;
			}
		}else{
			pos += 4;
		}
		String headerContent = content.substring(0, pos);
		String[] headrs = headerContent.replace("\r", "").split("\n");
		if(headrs[0].startsWith("GET ")){
			boolean isError = false;
			String resourcePath = headrs[0].substring(4, headrs[0].lastIndexOf(" "));
			File f = new File("."+resourcePath);
			if(f.exists()){
				String reply = "HTTP/1.1 200 OK\r\n"+
								"Server: pcap http server\r\n"+
								"Content-Type: text/html\r\n"+
								"Content-Length: "+f.length()+"\r\n"+
								"Accept-Ranges: bytes\r\n\r\n";
				s.buffer = ByteBuffer.allocate((int)(reply.getBytes().length+f.length()));
				s.buffer.put(reply.getBytes());
				try {
					readFileData(f, s.buffer);
				} catch (Exception e) {
					isError = true;
				}
			}else{
				isError = true;
			}
			
			if(isError){
				File errf = new File("./html/error/404.html");
				String reply = "HTTP/1.1 404\r\n"+
								"Server: pcap http server\r\n"+
								"Content-Type: text/html\r\n\r\n";
				s.buffer = ByteBuffer.allocate((int)(reply.getBytes().length+errf.length()));
				s.buffer.put(reply.getBytes());
				if(errf.exists()){
					try {
						readFileData(errf, s.buffer);
					} catch (Exception e) {
					}
				}
			}
			s.buffer.limit(0);
			s.buffer.position(0);
		}
		//String httpContent = content.substring(pos, content.length());
		
		
		return 0;
	}

	private static int calcBuff16BitsSum(byte[] buff, int off, int len){
		int checkSum = 0;
		for(int i=0; i<len;++i){
			checkSum += (i%2==0)?((buff[i+off]&0xff)<<8):(buff[i+off]&0xff);
		}
		return checkSum;
	}
	
	private static int calcBuffChecksum(byte[] buff, int off, int len){
		int checkSum = calcBuff16BitsSum(buff, off, len);
		return  (~(((checkSum>>16)&0xffff)+(checkSum&0xffff)))&0xffff;
	}
	
	private static int sendTcpReply(Pointer handle, byte[] remoteMacAddr, byte[] remoteAddr, int remotePort, 
			long identify, long sequenceId, long acknolegeId,
			boolean nonce, boolean cwr, boolean ecn, boolean urg, boolean ack, boolean push, boolean reset, boolean syn, boolean fin,
			byte[] data, int off, int len ){
		byte[] tcpBuff = new byte[2048];
		int ipPkgLen = 20+20+len; // no options
		System.arraycopy(remoteMacAddr, 0, tcpBuff, 0, 6); // dest mac
		System.arraycopy(localMacAddr, 0, tcpBuff, 6, 6); // src mac
		tcpBuff[12] = 8; tcpBuff[13] = 0;
		tcpBuff[14] = (byte)0x45; // ipv4 hdrlen 20
		tcpBuff[15] = 00;
		tcpBuff[16] = (byte)((ipPkgLen>>8)&0xff); tcpBuff[17] = (byte)(ipPkgLen&0xff); // ipPkgLen 
		tcpBuff[18] = (byte)((identify>>8)&0xff); tcpBuff[19] = (byte)(identify&0xff);  // protocol size
		tcpBuff[22] = 0x40; // ttl
		tcpBuff[23] = 6; // protocol tcp
		System.arraycopy(localIp, 0, tcpBuff, 26, 4); // sender ip
		System.arraycopy(remoteAddr, 0, tcpBuff, 30, 4); // target ip
		tcpBuff[34] = (byte)((localPort>>8)&0xff); tcpBuff[35] = (byte)(localPort&0xff); // src port
		tcpBuff[36] = (byte)((remotePort>>8)&0xff); tcpBuff[37] = (byte)(remotePort&0xff); // dest port
		tcpBuff[38] = (byte)((sequenceId>>24)&0xff);
		tcpBuff[39] = (byte)((sequenceId>>16)&0xff);
		tcpBuff[40] = (byte)((sequenceId>>8)&0xff);
		tcpBuff[41] = (byte)(sequenceId&0xff);
		tcpBuff[42] = (byte)((acknolegeId>>24)&0xff);
		tcpBuff[43] = (byte)((acknolegeId>>16)&0xff);
		tcpBuff[44] = (byte)((acknolegeId>>8)&0xff);
		tcpBuff[45] = (byte)(acknolegeId&0xff);
		tcpBuff[46] = (byte)((20<<2)&0xf0+(nonce?1:0));
		tcpBuff[47] = (byte)((cwr?0x80:0)+(ecn?0x40:0)+(urg?0x20:0)+(ack?0x10:0)+(push?0x08:0)+(reset?0x04:0)+(syn?0x02:0)+(fin?0x01:0));
		tcpBuff[48] = (byte)(0x7f);
		tcpBuff[49] = (byte)(0xff);
		if(data!=null){
			System.arraycopy(data, off, tcpBuff, 54, len);
		}
		int ipHdrChecksum = calcBuffChecksum(tcpBuff, 14, 20);
		int tcpCheckSum = calcBuff16BitsSum(tcpBuff, 26, 8);
		tcpCheckSum += 6+(20+len)+calcBuff16BitsSum(tcpBuff, 14+20, 20+len);
		tcpCheckSum = ~(((tcpCheckSum>>16)&0xffff)+(tcpCheckSum&0xffff));
		tcpBuff[24] = (byte)((ipHdrChecksum>>8)&0xff);
		tcpBuff[25] = (byte)(ipHdrChecksum&0xff);
		tcpBuff[50] = (byte)((tcpCheckSum>>8)&0xff);
		tcpBuff[51] = (byte)(tcpCheckSum&0xff);
		NativeMapping.pcap_sendpacket(handle, tcpBuff, ipPkgLen+14);
		return ipPkgLen+14;
	}
	
}

在代码根目录创建资源目录:

运行代码在虚拟机访问服务:

到这里手撸 tcp 协议栈 完整实现了一个基本的http服务器。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-07 12:25:58  更:2021-08-07 12:27:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:26:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码