在做web应用之前,你总是在本地安装一个Apache、Tomcat等软件,然后把完成的网页文件放到它们的工作目录下(比如Apachehtdocs),然后打开浏览器输入127.0.0.1或localhost直接访问。太神奇了,但是为什么,它是如何实现的呢?早就知道有Socket(套接字)了,只是之前没放这个。结合这两方面,今天我们就来看看这是为什么。有同学表示,还是不明白什么是Socket。这个东西很抽象。只有在计算机网络原理中讲协议的时候才会看到。今天我们完全忽略那些过于严谨和学术化的定义,让我们来看看什么是Socket。想象一下,你把电脑的电源插到插座上,你的电脑就可以使用了,为什么呢?您的计算机可以与千里之外的发电厂“通信”。将您的计算机视为客户端,将千里之外的发电厂视为服务器。通过socket和很长很长的电缆,你可以把它挂起来,那么这里面的Socket相当于什么?“插座!”没错,就是插座!我的电脑,我要它用电工作,我只需要一个插座,什么?插座是用什么做的,电缆是什么型号,供电厂的经纬度在哪里,电力是怎么传输的,我不管它做什么,都跟我没关系!我只需要知道,我需要的不是整个世界,而是整个世界。..一个插座!读到这里,同学们一定对“套接字”有了很好的认识;再举个例子,你和你朋友的电脑通过有线方式连接到同一个路由器。这时候就可以直接通过内网IP地址访问了。在此过程中,方形接口(RJ45接口)为“Socket”。反正插上“插座”就可以用了。我不关心如何通过Socket实现通信。在计算机编程的网络世界里,作为一个应用程序,我只需要一个“套接字”就可以与任何服务器通信。插上电源,发电厂也需要插上插座才能给你供电——也就是说,发电厂需要一个“插座”!..废话,,,,是的,没错,服务端也需要一个“socket”,不过叫ServerSocket(貌似是继承自Socket的,不知道,待查)。有了“Socket”的概念,我们就可以愉快的让电脑(客户端)和电厂(服务器)进行通信了。不管是客户端还是服务端,都需要Socket。由于我们今天的主题是“搭建网络服务器”,所以我们来看看如何为服务器创建一个ServerSocket。说到这里,有同学会问,客户端不需要Socket吗?确实有必要,因为我们是用浏览器访问本地IP“127.0.0.1”,所以客户端的Socket是浏览器自己维护的,不需要我们手写。“但是我还是不明白为什么在浏览器中输入127.0.0.1后就可以看到我的网页了?求解释。”好了,我们慢慢来,先写一个服务器端的ServerSocket。下面我们来创建一个服务器端Socket的步骤如下:1.创建一个ServerSocket对象ServerSocketserverSocket=newServerSocket("80");//这里,只需要说明当前程序监听80端口即可,至于为什么是80,因为我喜欢!“很霸道……”因为我们要监听web请求,默认是80端口.其实1-1024端口是被操作系统占用的,1025-65535端口只要不和其他应用冲突就可以使用(3389这种常用端口不要用...)2。作为服务端,我需要知道我的任务是等待客户端发送请求,也就是客户端发送一个Socket,我必须先hold住!套接字socket=serverSocket.accept();//这里需要特别说明一下,accept方法比较特殊,它是一个阻塞方法(blockmethod),因为只要等不及客户端发来的请求(Socket),它就会一直等下去继续执行它下面的代码。唉,为什么像我这样的恋人?O(∩_∩)O3。如果client要向我表白,给我发情书,那么作为server,我只需要得到它的输入即可。InputStreaminputStream=socket.getInputStream();//注意客户端发送的告白信息是在socket中,而不是在serverSocket中。如果写错了,看不懂情书的内容,活该单身。(我只是冷笑...)4.收到情书后,好想知道里面写的是什么!按!不!等待!OK,开始解析情书的内容BufferedReaderreader=newBufferedReader(newInputStreamReader(inputStream));//java封装类,只为阅读写给我的情书,yeah~Stringline="";while((line=reader.readLine())!=null){System.out.println(line);}5.组装前4步的代码,会要求你尝试捕获异常,可以正常捕获Socketsocket=serverSocket.accept();System.out.println("收到情书,我要开始解析了!");InputStreaminputStream=socket.getInputStream();BufferedReaderreader=newBufferedReader(newInputStreamReader(inputStream));Stringline="";while((line=reader.readLine())!=null){System.out.println(line);}}catch(Exceptione){e.printStackTrace();}}}好了,我们已经完成了服务端的编写——边码,你接下来要做什么?我不知道。..不过还记得刚才提出的问题——“可是我还是不明白为什么在浏览器中输入127.0.0.1就可以看到我的网页了?”如果输入127.0.0.1或localhost会怎样?首先,你必须运行我们刚才写的服务器端程序,然后打开浏览器。记住,必须先运行服务器端程序,否则情书就会丢失。..运行服务端程序,如图:注意红圈中的两点:由于此时客户端没有发送情书,还记得accept()的block方法吗现在,就是等啊等,没来我就等,所以红圈会显示“等情书……”;那么那个指向右边的箭头是什么意思,一个红色的停止图标,也就是说这个程序现在一直在执行,还没有结束,好像死了和循环一样(当然肯定不是死循环,其实是阻塞的,不过看起来像死循环,死循环后面再说,别着急,早晚会死的)接下来打开浏览器,在地址栏输入127.0.0.1/index.html并按Enter以查看浏览器如何响应。....过了一会儿,浏览器完全没有反应,然后告诉我页面无法显示。我去。..难道我们说了这么多都失败了,我哭了。然后打开eclipse看一下server端有没有动静。打开服务器一看,妈的,瞬间全世界都迎接我了!注意红笔标记,我收到情书了!我要开始解析了!那就别问我情书里写的是什么,继续往下看。“好熟悉的报文,我们好像在哪里见过,记得,那是一个春天,你刚刚发芽……”没错,这就是计算机网络原理中的HTTP请求报文。没学过物联网也没关系,看前两行(其实后面我们只会用到第一行),“Isawindex.html”是的,这就是我们刚刚在浏览器中输入地址;第二行,“Ialsosaw127.0.0.1”,没错,也是我们刚刚在浏览器中输入的。这是什么意思?我太激动了,我不能说这是什么意思,但我想你,读者,已经猜到了一些东西。写到这里,作为服务端的我已经收到了客户端的情书,为什么客户端(浏览器)一点反应都没有,甚至隔了一段时间还是“页面无法显示”。因为,有人给你写了一封情书,你却没有给他回信。等了一会儿,他心痛的是,什么都没有!是的,你要告诉他你喜不喜欢,给他一个答案。就说:“对不起,你是个好人……”你分心了吗?你好像在说你自己?回来,我们现在的任务是如何给人们一个答案。怎么给,怎么给,怎么给。..快想想,既然人家在127.0.0.1中指定要告白“index.html”,那么index.html当然要回答他。怎么回答,怎么回答,怎么回答。..快想想,既然index.html是一个文件,难道我不能读取文件的内容直接发送给客户端吗?但是送什么呢?没错,就是插座!我们使用sockets将文件内容返回给客户端就好了。那么问题来了。..“很好,关键是怎么做!”——如何先读取文件?假设我们的index.html在我电脑的E://courseware/computernetworkprinciple/experiment/experiment1/文件夹下,并且假设不会跨域访问,那么:1.定义一个字符串来存放我们的workingdirectoryStringbase_url="E://courseware/computernetworkprinciples/experiment/experiment1/";//这只是我原来电脑的目录,至于你的电脑,你可以自己改2.我怎么通过消息知道client要向index.html表白呢?看情书第一行GET/index.htmlHTTP/1.1,所以只需要获取情书第一行,解析出index.html,easy,let'sstart//因为只有第一行目前需要,所以我们不要像上面那样循环读取,读取一行就够了Stringline=reader.readLine();//使用字符串截取函数提取字符串"index.html"Stringurl=line.substring(5,line.indexOf("HTTP")-1);3.所以我们的index.html的绝对路径就是base_url+url。终于,我从人海中找到了我爱的人。看她怎么回答我——获取文件内容inputStream=newFileInputStream(base_url+url);OutputStreamoutputStream=socket.getOutputStream();//我想从服务器回复给客户端。对于服务器来说,这是发送的内容,所以Out了!byte[]buffer=newbyte[4*1024];//定义字节缓冲区intlen=0;while((len=inputStream.read(buffer))!=-1){outputStream.write(buffer,0,len);//很重要!通过socket的outputStream,将我们解析出来的文件内容一字不差的发送出去。如果你不写这个,它会导致你所爱的人向你表白并抑郁而死。你活该单}outputStream.flush();//如果上次写的时候没放bu如果ffer已满,则不会自动发送。您需要调用flush方法强制从缓冲区发送内容。文件读取完成后返回给客户端。亲爱的,他能接受吗?还是一样,一定要先运行服务器端程序,然后打开浏览器输入127.0.0.1/index.html回车。我又紧张又兴奋。我能收到回复吗?我会得到什么样的回复?如图所示。..为什么是这样???!!!好吧,让我们看看女神的index.html文件里写的是什么。..
