互联网技术及应用实践
实验报告
报告名称: 路由器配置及应用
路由追踪的实现 EMAIL的客户端程序 开发一个简单的WEB服务器
学生姓名:
学 号: 指导教师:
实验一 路由器配置及应用
1.实验原理
2.实验步骤
第一步:在路由器Router1上配置快速以太网口的IP地址
Router1#configure terminal
Router1(config)#interface FastEthernet 0/0 ! 进入以太网0口配置状态
或Router1(config)#interface FastEthernet 1/0
Router1(config-if)#ip address 172.16.1.1 255.255.255.0 ! 为以太网0口配置地址
Router1(config-if)#no shutdown ! 打开以太网0口 Router1(config-if)#end
第二步:在路由器Router1上配置广域网口的IP地址和时钟频率(假设Router1为DCE端)
Router1#con
Router1(config)#interface serial 2/0 ! 进入广域网0口配置状态 或Router1(config)#interface serial 1/2
Router1(config-if)#ip address 172.16.2.1 255.255.255.0 ! 为广域网0口配置地址
Router1(config-if)#clock rate 64000 ! DCE端需设置端口时钟频率 Router1(config-if)#no shutdown ! 打开广域网0口 Router1(config-if)#end
验证测试:验证路由器接口配置状态。
Router1#show ip interface brief ! 显示IP端口状态简况 Interface IP-Address OK? Method Status Protocol FastEthernet0/0 172.16.1.1/24 YES manual up up
FastEthernet0/1 no address YES unset administratively down down Serial2/0 172.16.2.1/24 YES manual up up
Serial3/0 no address YES unset administratively down down Null 0 no address YES up 第三步:为Router1添加静态路由
Router1#con
Router1(config)#ip route 172.16.3.0 255.255.255.0 172.16.2.2 ! 添加静态路由
Router1(config)#end
Router1#show ip route ! 显示路由表
Codes: C - connected, S - static, R - RIP O - OSPF, IA - OSPF inter area
E1 - OSPF external type 1, E2 - OSPF external type 2 Gateway of last resort is not set 172.16.0.0/24 is subnetted, 3 subnets
C 172.16.1.0 is directly connected, FastEthernet0 C 172.16.2.0 is directly connected, Serial0 S 172.16.3.0 [1/0] via 172.16.2.2 Router1#wr !保存所作的修改
第四步:在路由器Router2(R2624)上配置快速以太网口的IP地址
Router2#con
Router2(config)#interface fastethernet 0/0 或Router2(config)#interface fastethernet 1/0
Router2(config-if)#ip address 172.16.3.2 255.255.255.0 Router2(config-if)#no shutdown Router2(config-if)#end
第五步:在路由器Router2(R2624)上配置广域网口的IP地址
Router2#conf
Router2(config)#interface serial 2/0 或Router2(config)#interface serial 1/2
Router2(config-if)#ip address 172.16.2.2 255.255.255.0 Router2(config-if)#no shutdown Router2(config-if)#end
Router2#show ip interface brief
Interface IP-Address OK? Method Status Protocol FastEthernet0/0 172.16.3.2 YES manual up up
FastEthernet0/1 unassigned YES unset administratively down down Serial2/0 172.16.2.2 YES manual up up
Serial3/0 unassigned YES unset administratively down down 图下图:
图1.1
第六步:测试两台路由器之间的连通性
Router2#ping 172.16.2.1
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echoes to 172.16.2.1, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/4 ms
如下图:
图1.2
第七步:为Router2(R2624)添加静态路由
Router2#con
Configuring from terminal, memory, or network [terminal]? Enter configuration commands, one per line. End with CNTL/Z. Router2(config)#ip route 172.16.1.0 255.255.255.0 172.16.2.1 Router2(config)#end Router2#show ip route
Codes: C - connected, S - static, R - RIP O - OSPF, IA - OSPF inter area
E1 - OSPF external type 1, E2 - OSPF external type 2 Gateway of last resort is not set 172.16.0.0/24 is subnetted, 3 subnets S 172.16.1.0 [1/0] via 172.16.2.1
C 172.16.2.0 is directly connected, Serial0
C 172.16.3.0 is directly connected, FastEthernet0 Router2#wr 如下图:
图1.3
第八步:用ping命令对PC1,PC2进行连通性检测 如下图:
图1.4
注意事项:
(1)如果两台路由器经过串口直接相连,则必须在时钟一端设置时钟频率(DCE)。
(2)PC机必须配置默认网关。
实验二 路由追踪
1. 实验目的:
熟悉掌握路由器实现路由追踪,熟悉ICMP协议 2. 实验环境:
Microsoft Visual C++6.0 3.实验原理:
路由追踪是从源主机向目的主机发送一连串的IP数据报,数据包中封装的是无法交付的UDP数据报。源主机先向目的主机发送一个回应请求报文(类型8),TTL设置为1,第一个路由器收到后 将TTL设为1第一个路由器收到后将TTL减1,这样TTL变为0,分组被废除,同时路由器向源主机发送一个TTL超时报文(类型为11),报文的IP报头中的源IP地址就是第一个路由器的地址,源主机可以通过对该报文进行分析,得到第一个路由器的地址,接着发送TTL等于2的报文得到第二个路由器的地址,再发送TTL等于3的报文,如此下去直到收到目的主机的回应应答报文(类型为0)或不可到达报文(类型为3),或者到了最大跳数(要检测路由器个数的最大值)。这样,源主机达到了自己的目的,因为这些路由器和最后的目的主机发送的ICMP报文正好给源主机想知道的路由信息——到达目的主机所经过的路由器的IP地址,以及到达其中每一个路由器的往返时间。 4.源代码如下:
#define WIN32_LEAN_AND_MEAN
#include #include #include #define ICMP_ECHO 8 //发送Ping请求时的ICMP报文类型 #define ICMP_ECHOREPLY 0 //接收Ping回复时的ICMP报文类型 #define ICMP_TIMEOUT 11 //ICMP超时报文类型 #define ICMP_MIN 8 //Minimum 8-byte ICMP packet (header) #define MAX_PACKET 1024 //Max ICMP packet size #define DEICMP_PACKSIZE 44 //Defaut ICMP PACKET SIZE char lpdest[16]; //用来存放目的IP地址 DWORD cStartTickCount; //用来存放发送包的起始时间 #pragma comment( lib, \"ws2_32.lib\" ) typedef struct _icmphdr //ICMP头部定义,被封装在IP包中 { BYTE i_type; //报文类型 BYTE i_code; //代码 USHORT i_cksum; //校验和 USHORT i_id; //标识符 USHORT i_seq; //序号 }IcmpHeader; //初始化ICMP头部 void FillICMPData(char *icmp_data,int datasize) { IcmpHeader *icmp_hdr=NULL; char *datapart=NULL; icmp_hdr=(IcmpHeader *)icmp_data; icmp_hdr->i_type=ICMP_ECHO; //request an ICMP echo icmp_hdr->i_code=0; icmp_hdr->i_id=(USHORT)GetCurrentProcessId(); icmp_hdr->i_cksum=0; icmp_hdr->i_seq=0; datapart=icmp_data+sizeof(IcmpHeader); memset(datapart,'E',datasize-sizeof(IcmpHeader)); } //校验和函数 USHORT checksum(USHORT *buffer,int size) { unsigned long cksum=0; while(size>1) { cksum+=*buffer++; size-=sizeof(USHORT); } if(size) cksum+=*(UCHAR *)buffer; cksum=(cksum>>16)+(cksum & 0xffff); cksum+=(cksum>>16); return (USHORT)(~cksum);; } int DecodeIPHeader(char *buf,int bytes,struct sockaddr_in *from) { IcmpHeader *icmphdr=NULL; DWORD tick; static int icmpcount=1; unsigned short iphdrlen; //判断接收操作是否超时 if(!buf) { printf(\"%2d: ***.***.***.*** Request timed out.\\n\ return 1; } tick=GetTickCount(); iphdrlen=(buf[0] & 0x0f)*4; icmphdr=(IcmpHeader *)(buf+iphdrlen); if(bytes return 0; } //判断接收的ICMP报文是否为超时报文 if(icmphdr->i_type==ICMP_TIMEOUT&&icmphdr->i_code==0) { printf(\"%2d: %-15s %4dms\\n\cStartTickCount); return 0; } //判断接收的ICMP报文是否为回复报文 else if(icmphdr->i_type==ICMP_ECHOREPLY&&icmphdr->i_id==GetCurrentProcessId()) { printf(\"%2d: %-15s %4dms\\n\cStartTickCount); printf(\"Trace complete!\\n\"); return 1; } //其他类型,表示不可达 else { printf(\"%2d: Destination host is unreachable!\\n\ return 1; } } int main() { WSADATA wsaData; SOCKET sockRaw=INVALID_SOCKET; struct sockaddr_in dest, from; int i,bread,fromlen=sizeof(from),timeout=1000,ret; struct hostent *hp=NULL; char *icmp_data=NULL,*recvbuf=NULL; USHORT seq_no=0; printf(\"Destination Address(IP/Host name):\"); scanf(\"%s\ if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0) { printf(\"WSAStartup() failed:%d\\n\ return -1; } //创建套接字 sockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED); if(sockRaw==INVALID_SOCKET) { printf(\"WSASocket() failed:%d\\n\ return -1; } //对锁定套接字设置超时 bread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(timeout)); if(bread==SOCKET_ERROR) { printf(\"setsockopt(SO_RCVTIMEO) failed:%d\\n\ return -1; } timeout=1000; bread=setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(timeout)); if(bread==SOCKET_ERROR) { printf(\"setsockopt(SO_SNDTIMEO) failed:%d\\n\ return -1; } //解析目标地址,将主机名转化为IP地址 memset(&dest,0,sizeof(dest)); dest.sin_family=AF_INET; if((dest.sin_addr.S_un.S_addr=inet_addr(lpdest))==INADDR_NONE) { if((hp=gethostbyname(lpdest))!=NULL) { memcpy(&(dest.sin_addr.S_un.S_addr),hp->h_addr_list[0],hp->h_length); dest.sin_family=hp->h_addrtype; printf(\"dest.sin_addr=%s\\n\ } else { printf(\"gethostbyname() failed:%d\\n\ return -1; } } //Create the ICMP pakcet icmp_data= (char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET); recvbuf = (char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET); if(!icmp_data) { printf(\"HeapAlloc() failed: %d\\n\ return -1; } memset(icmp_data,0,MAX_PACKET); FillICMPData(icmp_data,DEICMP_PACKSIZE); printf(\"Hop IP Address Time elapsed\\n\"); //开始发送/接收ICMP报文 for(i=1;i<=255;i++) { int bwrote; //设置IP包的生存期 ret=setsockopt(sockRaw,IPPROTO_IP,IP_TTL,(char *)&i,sizeof(int)); if(ret==SOCKET_ERROR) { printf(\"setsockopt(IP_TTL) failed:%d\\n\ } ((IcmpHeader *)icmp_data)->i_cksum =0; ((IcmpHeader *)icmp_data)->i_seq=seq_no++; //Sequence number of ICMP packets ((IcmpHeader *)icmp_data)->i_cksum=checksum((USHORT *)icmp_data,DEICMP_PACKSIZE); //发送ICMP包请求查询 cStartTickCount=GetTickCount(); bwrote=sendto(sockRaw,icmp_data,DEICMP_PACKSIZE,0,(struct sockaddr *)&dest,sizeof(dest)); if(bwrote==SOCKET_ERROR) { if(WSAGetLastError()==WSAETIMEDOUT) { printf(\"timed out\\n\"); continue; } printf(\"sendto() failed:%d\\n\ return -1; } if(bwrote //接收ICMP回复包 bread=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr *)&from,&fromlen); if(bread==SOCKET_ERROR) { if(WSAGetLastError()==WSAETIMEDOUT) { DecodeIPHeader(NULL,0,NULL); continue; } printf(\"recvfrom() failed:%d\\n\ return -1; } if(DecodeIPHeader(recvbuf,bread,&from)) break; Sleep(1000); } system(\"pause\"); if(sockRaw!=INVALID_SOCKET) closesocket(sockRaw); HeapFree(GetProcessHeap(),0,recvbuf); HeapFree(GetProcessHeap(),0,icmp_data); WSACleanup(); return 0; } 5.实验结果如图: 实验三 EMAIL的客户端程序 1.代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Net.Mail; using System.Net.Sockets; using System.IO; namespace mail { /// /// MainWindow.xaml 的交互逻辑 /// public partial class MainWindow : Window { TcpClient server;//接服务器 string sendstring;//用于存储POP3服务命令参数 byte[] bufferstring;//用于存储POP3服务命令参数字节数 NetworkStream networkstream;//接服务器与服务器进行数据交互 StreamReader streamreader;//读取信息数据 public MainWindow() { InitializeComponent(); } private void sendMail_Click(object sender, RoutedEventArgs e) { //SmtpClient client = new SmtpClient(\"smtp.qq.com\"); SmtpClient client = new SmtpClient(\"smtp.163.com\"); client.Port = 25; MailMessage mail = new MailMessage(); mail.From = new MailAddress(\"liuweituan1989@163.com\我是1234\");//加上自定义的发件人显示名称 mail.To.Add(new MailAddress(\"120172167@qq.com\")); mail.Subject = \"Test SmtpClient\"; mail.Body = \"This message is for testing.\"; client.DeliveryMethod = SmtpDeliveryMethod.Network; client.UseDefaultCredentials = true; //启用身份认证 mail.Priority = MailPriority.Normal; //邮件优先级 //mail.Attachments.Add(new Attachment(@\"F:\\我的文档\\消息.txt\")); //附件 //mail.Body = new System.IO.StreamReader(@\"F:\\我的文档\\ttt.txt\从文本文件中读取邮件内容 mail.BodyEncoding = System.Text.Encoding.UTF8; client.Credentials = new System.Net.NetworkCredential(\"liuweituan1989@163.com\ \"19891217421X\");//如果是匿名发送则不需要这一句(这里将账号和密码用x和*代替了) // client.Send(mail); client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);//回调函数 string userState = \"测试\"; client.SendAsync(mail, userState); } private static void SendCompletedCallback(object sender, System.ComponentModel.AsyncCompletedEventArgs e) { if (e.Cancelled) //邮件发送被取消 { } if (e.Error != null) //邮件发送失败 { } else //发送成功 { } } private void Showinfo() { richTextBox1.Document.Blocks.Clear(); try { string strResult = \"\"; sendstring = \"RETR \" + this.textBox4.Text + \"\\r\\n\";//存储从服务器获得一条信息的命令 bufferstring = Encoding.ASCII.GetBytes(sendstring.ToCharArray()); networkstream.Write(bufferstring, 0, bufferstring.Length); strResult = streamreader.ReadLine(); if (strResult[0] != '-') { //不断地读取邮件内容,只到结束标志:英文句号 while (strResult != \".\") { this.richTextBox1.AppendText(strResult + \"\\r\\n\"); strResult = streamreader.ReadLine(); } } else { this.richTextBox1.AppendText(\"\\r\\n\" + \"邮件错误\" + \"\\r\\n\"); } } catch (Exception ey) { MessageBox.Show(ey.Message); } } private void getMail_Click(object sender, RoutedEventArgs e) { Showinfo(); } private void login_Click(object sender, RoutedEventArgs e) { server = new TcpClient(this.textBox1.Text, 110);//实例TcpClient 类对象联接服务器 networkstream = server.GetStream();//实例NetworkStream类对象接收返回发送的数据 streamreader = new StreamReader(networkstream);//实例StreamReader类对象读取数据 try { sendstring = \"USER \" + this.textBox2.Text + \"\\r\\n\";//存储用户名 bufferstring = Encoding.GetEncoding(\"gb2312\").GetBytes(sendstring.ToCharArray()); networkstream.Write(bufferstring, 0, bufferstring.Length);//将用户名发送到服务器 richTextBox1.AppendText(streamreader.ReadLine() + \"\\r\\n\");//将用用户显示在 richTextBox控件中 sendstring = \"PASS \" + this.textBox3.Text + \"\\r\\n\";//存储用户密码 bufferstring = Encoding.GetEncoding(\"gb2312\").GetBytes(sendstring.ToCharArray()); networkstream.Write(bufferstring, 0, bufferstring.Length);//将用户密码发送到服务器 richTextBox1.AppendText(streamreader.ReadLine() + \"\\r\\n\"); sendstring = \"STAT \" + \"\\r\\n\";//储存从服务器获得所有信息序号和字节数命令 bufferstring = Encoding.GetEncoding(\"gb2312\").GetBytes(sendstring.ToCharArray()); networkstream.Write(bufferstring, 0, bufferstring.Length);//从服务器获得所有信息序号和字节数 string strResult = streamreader.ReadLine();//读取从服务器返回的数据 if (strResult.IndexOf('-') == -1) { richTextBox1.AppendText(strResult + \"\\r\\n\"); sendstring = \"LIST \" + \"\\r\\n\";//存储从服务器中获得信息列表和大小的命令 bufferstring = Encoding.GetEncoding(\"gb2312\").GetBytes(sendstring.ToCharArray()); networkstream.Write(bufferstring, 0, bufferstring.Length); string strInfo = streamreader.ReadLine(); string[] str = strInfo.Split(' '); richTextBox1.AppendText(\"邮件数量:\" + str[1] + \"\\r\\n\"); richTextBox1.AppendText(str[1] + \":封邮件总容量为\" + str[2] + \"\\r\\n\"); MessageBox.Show(this.textBox2.Text + \"用户您好!!!\"); } else { MessageBox.Show(\"读取信息有误,请重新登录\"); } } catch (Exception ey) { MessageBox.Show(ey.Message); } } } } 2.实验结果: 实验四 简单的WEB服务器开发 1. 实验目的 了解web服务器的实现原理,并编程实现一个简单的web服务器。 2.开发环境 Windows xp操作系统 Java语言编程 3.实验原理 WWW是以Internet作为传输媒介的一个应用系统,WWW网上最基本的传输单位是Web网页。WWW的工作基于客户机/服务器计算模型,由Web 浏览器(客户机)和Web服务器(服务器)构成,两者之间采用超文本传送协议(HTTP)进行通信。HTTP协议是基于TCP/IP协议之上的协议,是Web浏览器和Web服务器之间的应用层协议,是通用的、无状态的、面向对象的协议。HTTP协议的作用原理包括四个步骤:连接,请求,应答,关闭应答。 根据上述HTTP协议的作用原理,实现GET请求的Web服务器程序的方法如下: (1) 创建ServerSocket类对象,监听端口8080。这是为了区别于HTTP的标准TCP/IP端口80而取的; (2) 等待、接受客户机连接到端口8080,得到与客户机连接的socket; (3) 创建与socket字相关联的输入流instream和输出流outstream; (4) 从与socket关联的输入流instream中读取一行客户机提交的请求信息,请求信息的格式为:GET 路径/文件名 HTTP/1.0 (5) 从请求信息中获取请求类型。如果请求类型是GET,则从请求信息中获取所访问的HTML文件名。没有HTML文件名时,则以index.html作为文件名; (6) 如果HTML文件存在,则打开HTML文件,把HTTP头信息和HTML文件内容通过socket传回给Web浏览器,然后关闭文件。否则发送错误信息给Web浏览器; (7) 关闭与相应Web浏览器连接的socket字。 可以总结出Web服务器的设计流程并作出其设计流程图,如图4-1所示。 图4-1 Web服务器的程序设计流程 4.主要代码如下 在Java工程中建立包webserver和类HttpServer、Request、Response,在对应框中输入以下程序代码: -------------------------HttpServer.java------------------------------- package webserver; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Properties; import java.io.IOException; import java.util.Enumeration; import java.net.ServerSocket; import java.net.Socket; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; public class HttpServer { private int iPort = 8080; //default port public static String Basic_Root=System.getProperty(\"user.dir\"); public static String WEB_ROOT = System.getProperty(\"user.dir\") + File.separator + \"webroot\"; public static int count=0; public HttpServer() { System.out.println(\"欢迎使用Web服务器,本服务器只支持静态网页。\"); System.out.println(\"检查配置文件及网页文件夹...\"); getConfig(); start(); } public static void main(String[] args) { HttpServer httpserver = new HttpServer(); } private void getConfig() { File fileCon=new File(Basic_Root,\"config.ini\"); File fileDir=new File(WEB_ROOT); File fileWeb=new File(WEB_ROOT,\"index.htm\"); if(!fileCon.exists()) { System.out.println(\"配置文件Config.ini损坏,重建中...\"); reBuildConfig(fileCon); } if (!fileDir.exists()) { System.out.println(\"网页存放文件夹不存在,重建中...\"); fileDir.mkdir(); System.out.print(\"完成!请在\"); System.out.println(WEB_ROOT+\"中放置网页文件...\"); System.out.println(\"Web服务器将重新初始化...\"); getConfig(); } if (!fileWeb.exists()) { reBuildWeb(fileWeb); } Properties pps = new Properties(); try { pps.load(new FileInputStream(\"config.ini\")); Enumeration enumer = pps.propertyNames(); String strKey = (String) enumer.nextElement(); String strValue = pps.getProperty(strKey); if (strValue.equals(\"\") != true) { WEB_ROOT = strValue; } System.out.println(\"网页文件的存放路径为: \"+WEB_ROOT); strKey = (String) enumer.nextElement(); strValue = pps.getProperty(strKey); if (strValue.equals(\"\") != true) { iPort = Integer.parseInt(strValue); } System.out.println(\"Web服务器访问端口为:\"+iPort); System.out.println(\"您可以修改Config.ini文件重新设定以上配置\"); System.out.println(\"启动检查完成,服务器初始化中...\"); } catch (IOException ex) { ex.printStackTrace(); } } public void start() { System.out.println(\"Web 服务器启动中...\"); ServerSocket serverSocket; try { serverSocket = new ServerSocket(iPort); System.out.println(\"Web 启动完成!\"); System.out.println(\"您现在可以在浏览器中访问http://localhost:8080/,以测试服务器是否运行\"); while (true) { Socket socket = null; InputStream input = null; OutputStream output = null; System.out.println(\"等待连接...\"); socket = serverSocket.accept(); System.out.println(socket.getInetAddress().toString()+\"请求连接\"); input=socket.getInputStream(); output=socket.getOutputStream(); System.out.println(\"服务器开始处理第\"+(++count)+\"次连接\"); //开始处理并分析请求信息 Request request=new Request(input); request.parse(); //开始发送请求资源 Response response=new Response(output); response.setRequest(request); response.sendStaticResource(); //关系连接 socket.close(); System.out.println(\"连接已关闭!\"); } } catch(Exception ex) { ex.printStackTrace(); System.out.println(\"3\"); //continue; } } private void reBuildConfig(File file) { try { file.createNewFile(); FileOutputStream fos=new FileOutputStream(file); PrintStream sp=new PrintStream(fos); sp.println(\"WEB_ROOT=\"); sp.println(\"PORT=\"); sp.close(); System.out.println(\"配置文件Config.ini创建成功,您可以修改WEB_ROOT的值改变网页文件的存放路径,修改PORT的值改变访问端口!\"); } catch (IOException ex) { ex.printStackTrace(); System.out.println(\"重建配置文件Config.ini失败\"); System.out.println(\"服务器将使用默认配置...\"); } } private void reBuildWeb(File file) { try { file.createNewFile(); FileOutputStream fos=new FileOutputStream(file); PrintStream sp=new PrintStream(fos); sp.println(\"\"); sp.println(\" sp.println(\" sp.println(\" sp.println(\"\"); sp.println(\"\"); sp.close(); } catch (Exception ex) { ex.printStackTrace(); } } } -----------------------Request.java------------------------------------ package webserver; import java.io.InputStream; public class Request { public Request() { } private InputStream input; private String uri; public Request(InputStream input) { this.input = input; } public void parse()//取得请求信息 { StringBuffer request = new StringBuffer(2048); int i; byte[] buffer = new byte[2048]; try { i = input.read(buffer); } catch (Exception ex) { ex.printStackTrace(); i = -1; } for (int j = 0; j < i; j++) { request.append((char) buffer[j]); } System.out.println(request.toString()); uri = parseUri(request.toString()); System.out.println(\"用户请求:\"+this.getUri()); } private String parseUri(String requestString)//分析请求信息,并返回 { int index1, index2; index1 = requestString.indexOf(\" \"); if (index1 != -1) { index2 = requestString.indexOf(\" \ if (index2 > index1) { return requestString.substring(index1 + 1, index2); } } return null; } public String getUri() { if (uri.compareTo(\"/\")==0) { uri=\"/index.htm\"; } if (uri.indexOf(\".\")==-1) { uri+=\".htm\"; } return uri; } } ----------------------------Response.java------------------------------ package webserver; import java.io.OutputStream; import java.io.IOException; import java.io.FileInputStream; import java.io.File; public class Response { private static final int BUFFER_SIZE = 1024; Request request; OutputStream output; public Response(OutputStream output) { this.output = output; } public void setRequest(Request request) { this.request = request; } public void sendStaticResource()//发送请求资源 throws IOException { byte[] bytes = new byte[BUFFER_SIZE]; FileInputStream fis = null; try { File file = new File(HttpServer.WEB_ROOT, request.getUri()); if (file.exists()) { System.out.println(\"开始发送用户请求资源...\"); fis = new FileInputStream(file); int ch = fis.read(bytes, 0, BUFFER_SIZE); while (ch != -1) { output.write(bytes, 0, ch); ch = fis.read(bytes, 0, BUFFER_SIZE); } System.out.println(\"发送完毕!\"); } else { System.out.println(\"用户请求的资源不存在\"); String errorMessage = \"HTTP/1.1 404 File Not Found\\r\\n\" + \"Content-Type:text/html\\r\\n\" + \"\\r\\n\" + \" catch (Exception ex) { ex.printStackTrace(); System.out.println(\"获取请求资源错误,请检查本地资源设置!\"); System.exit(1); } if (fis != null) { fis.close(); } } } 5.程序运行结果如下 为了确保上述程序的正确性,进行调试运行,在工程文件的webroot中建立html文件,在index.html文件中输入“服务器已经成功运行”如下图4.1所示。 图4.1在index.html文件中如图字样 右击运行HttpServer服务器结果显示为如图4.2所示: 图4.2 运行应用程序的结果 应用程序窗口显示,等待连接,/127.0.0.1请求连接,服务器处理连接,用户请求:/index.html,开始发送用户请求资源,发送完毕,连接关闭。内容如图4.3所示: 图4.3运行应用程序后结果 因篇幅问题不能全部显示,请点此查看更多更全内容