本文鏈接:https://blog.csdn.net/lingyunhappy/article/details/77683591
在寫一個socket編程的測試類的時候,發散了一下思維,想到這個Socket編程有什么用?在實際的應用中都使用Tomcat作為服務器,Tomcat支持的請求協議是HTTP協議,跟Socket有什么關系?Tomcat中究竟有沒有使用Socket編程?是如何使用的?瀏覽器能夠new出一個Socket發送給服務器嗎?瀏覽器每次向服務器請求都會遵照TCP/IP協議的三次握手嗎?
找了一些帖子,找出對回答以上問題有幫助的梳理了一下
一、Java網絡編程之TCP通信
http://www.cnblogs.com/xujian2014/p/4660570.html
這個帖子確定了Socket使用的是TCP/IP協議
1.概念概述
Socket類是Java執行客戶端TCP操作的基礎類,這個類本身使用代碼通過主機操作系統的本地TCP棧進行通信。Socket類的方法會建立和銷毀連接,設置各種Socket選項
ServerSocket類是Java執行服務端TCP操作的基礎類,該類運行與服務器,監聽入站的TCP連接,每個socket服務器監聽服務器的某個端口,當遠程主機的客戶端嘗試連接到此端口時,服務器被喚醒,並返回一個表示兩台主機之間socket的Socket對象。
TCP是一種面向連接,可靠的、基於字節流的傳輸層通信協議。TCP通信分為客戶端和服務器端,對應的對象分別是Socket和ServerSocket。
當一台計算機需要與另一台計算機連接時,TCP協議會讓它們建立一個連接:用於發送和接受數據的虛擬鏈路。TCP協議負責收集信息包,並將其按照適當的次序放好傳送,當接收端收到后再將其正確的還原。為了保證數據包再傳送中准確無誤,TCP使用了重發機制:當一個通信實體發送一個消息給另一個通信實體后需要收到另一個實體的確認消息,如果沒有收到消息,則會再次重發剛才發送的消息。
2.TCP通信
Socket類實現客戶端套接字
Socket s=new Socket(“127.0.0.1”, 10001);//創建一個流套接字並將其連接到指定主機上的指定端口號
ServerSocket類實現服務器套接字
ServerSocket ss=new ServerSocket(10001);//創建綁定到特定端口的服務器套接字
3.Socket在瀏覽上的應用
在Eclipse中編寫服務器端,然后利用瀏覽器進行訪問。
public class SocketServer { public static void main(String[] args) throws IOException { ServerSocket server=new ServerSocket(11000); Socket client=server.accept(); PrintWriter out=new PrintWriter(client.getOutputStream(),true); BufferedReader in=new BufferedReader(new InputStreamReader(client.getInputStream())); String line=null; while((line=in.readLine())!=null) System.out.println(line); out.println("你好!"); server.close(); } }
GET / HTTP/1.1 Host: 10.38.48.195:11000 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3357.400 QQBrowser/9.6.11858.400 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8 Accept-Encoding: gzip, deflate, sdch Accept-Language: zh-CN,zh;q=0.8 Cache-Control: max-age=0 Proxy-Connection: keep-alive Upgrade-Insecure-Requests: 1 X-Lantern-Version: 3.7.4
二、Java基於socket服務實現UDP協議的方法
http://www.jb51.net/article/66979.htm
這個帖子說明了基於Socket的也可以使用UDP協議
package com.maven.test.net; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; public class UDPServer02 { public static void main(String[] args) throws IOException{ System.out.println("接收端啟動…………"); /* 2、建立UDP的socket的服務,必須明確一個端口號 3、創建數據包,用於儲存接收到的數據,方便用數據包對象的方法解析這些數據 4、使用DatagramSocket的receive方法將接收到的數據存儲到數據包中 5、通過數據包的方法解析數據包中的數據 5、關閉socket服務 */ //udpsocket服務,使用DatagramSocket對象 DatagramSocket ds=new DatagramSocket(10003); while(true){ //使用DatagramPacket將數據封裝到該對象中 byte[] buf=new byte[1024]; DatagramPacket dp=new DatagramPacket(buf, buf.length); //通過udp的socket服務將數據包發送出去,通過send方法 ds.receive(dp);//阻塞式的。 //通過數據包的方法解析數據包中的數據,比如,地址、端口、數據內容等 String ip=dp.getAddress().getHostAddress(); //String name=dp.getAddress().getHostName(); int port=dp.getPort(); String text=new String(dp.getData(),0,dp.getLength()); //System.out.println("-----"+ip+"-----"+name+"-----"+port+"-----"+text); System.out.println("-----"+ip+"----------"+port+"-----"+text); } //關閉資源 //ds.close(); } } package com.maven.test.net; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class UDPClient02 { public static void main(String[] args) throws IOException{ System.out.println("發送端啟動…………"); /* * 1、創建udp傳輸的發送端 2、建立UDP的socket的服務 3、將要發送的數據封裝到數據包中 4、通過udp的socket服務將數據包發送出去 5、關閉socket服務 */ //udpsocket服務,使用DatagramSocket對象 DatagramSocket ds=new DatagramSocket(9999);//監聽端口 //將要發送的數據封裝到數據包中 //String str="udp傳輸演示,go"; BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));//鍵盤輸入 String line=null; //使用DatagramPacket將數據封裝到該對象中 while((line=bufr.readLine())!=null){ byte[] buf=line.getBytes();// DatagramPacket dp= new DatagramPacket(buf, buf.length,InetAddress.getByName("127.0.0.1"),10003); //通過udp的socket服務將數據包發送出去,通過send方法 ds.send(dp); if("886".equals(line)){ break; } } //關閉資源 ds.close(); } }
三、Socket與Servlet的簡單理解
http://blog.csdn.net/sdjkjsdh/article/details/51569481
Servlet是Socket的一種應用,在每次請求時,會產生三次握手
1、 Socket:使用TCP/IP或者UDP協議在服務器與客戶端之間進行傳輸的技術,是網絡編程的基礎
Servlet:使用http協議在服務器與客戶端之間通信的技術。是Socket的一種應用。
2、 tcp/ip協議:關注的是客戶端與服務器之間的數據傳輸是否成功(三次握手,傳輸失敗會重發)
http協議:是在tcp/ip協議之上進一步封裝的一層協議,關注的事數據傳輸的格式是否規范,底層的數據傳輸還是運用了socket和tcp/ip
四、Tomcat中使用Socket編程
在tomcat中找到了具體的處理Socket的Process類,確定了Tomcat的底層是Socket編程
org.apache.coyote.http11.Http11Processor.process(Socket)
public void process(Socket theSocket)
throws IOException {
RequestInfo rp = request.getRequestProcessor();
rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
// Set the remote address
remoteAddr = null;
remoteHost = null;
localAddr = null;
localName = null;
remotePort = -1;
localPort = -1;
// Setting up the I/O
this.socket = theSocket;
inputBuffer.setInputStream(socket.getInputStream());
outputBuffer.setOutputStream(socket.getOutputStream());
// Error flag
error = false;
keepAlive = true;
int keepAliveLeft = maxKeepAliveRequests;
int soTimeout = endpoint.getSoTimeout();
// When using an executor, these values may return non-positive values
int curThreads = endpoint.getCurrentThreadsBusy();
int maxThreads = endpoint.getMaxThreads();
if (curThreads > 0 && maxThreads > 0) {
// Only auto-disable keep-alive if the current thread usage % can be
// calculated correctly
if ((curThreads*100)/maxThreads > 75) {
keepAliveLeft = 1;
}
}
try {
socket.setSoTimeout(soTimeout);
} catch (Throwable t) {
log.debug(sm.getString("http11processor.socket.timeout"), t);
error = true;
}
boolean keptAlive = false;
while (started && !error && keepAlive && !endpoint.isPaused()) {
// Parsing the request header
try {
if (keptAlive) {
if (keepAliveTimeout > 0) {
socket.setSoTimeout(keepAliveTimeout);
}
else if (soTimeout > 0) {
socket.setSoTimeout(soTimeout);
}
}
inputBuffer.parseRequestLine();
request.setStartTime(System.currentTimeMillis());
keptAlive = true;
if (disableUploadTimeout) {
socket.setSoTimeout(soTimeout);
} else {
socket.setSoTimeout(timeout);
}
// Set this every time in case limit has been changed via JMX
request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());
inputBuffer.parseHeaders();
} catch (IOException e) {
error = true;
break;
} catch (Throwable t) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("http11processor.header.parse"), t);
}
// 400 - Bad Request
response.setStatus(400);
adapter.log(request, response, 0);
error = true;
}
if (!error) {
// Setting up filters, and parse some request headers
rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
try {
prepareRequest();
} catch (Throwable t) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("http11processor.request.prepare"), t);
}
// 400 - Internal Server Error
response.setStatus(400);
adapter.log(request, response, 0);
error = true;
}
}
if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0)
keepAlive = false;
// Process the request in the adapter
if (!error) {
try {
rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
adapter.service(request, response);
// Handle when the response was committed before a serious
// error occurred. Throwing a ServletException should both
// set the status to 500 and set the errorException.
// If we fail here, then the response is likely already
// committed, so we can't try and set headers.
if(keepAlive && !error) { // Avoid checking twice.
error = response.getErrorException() != null ||
statusDropsConnection(response.getStatus());
}
} catch (InterruptedIOException e) {
error = true;
} catch (Throwable t) {
log.error(sm.getString("http11processor.request.process"), t);
// 500 - Internal Server Error
response.setStatus(500);
adapter.log(request, response, 0);
error = true;
}
}
// Finish the handling of the request
try {
rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
// If we know we are closing the connection, don't drain input.
// This way uploading a 100GB file doesn't tie up the thread
// if the servlet has rejected it.
if(error)
inputBuffer.setSwallowInput(false);
inputBuffer.endRequest();
} catch (IOException e) {
error = true;
} catch (Throwable t) {
log.error(sm.getString("http11processor.request.finish"), t);
// 500 - Internal Server Error
response.setStatus(500);
// No access logging since after service method
error = true;
}
try {
rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
outputBuffer.endRequest();
} catch (IOException e) {
error = true;
} catch (Throwable t) {
log.error(sm.getString("http11processor.response.finish"), t);
error = true;
}
// If there was an error, make sure the request is counted as
// and error, and update the statistics counter
if (error) {
response.setStatus(500);
}
request.updateCounters();
rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
// Don't reset the param - we'll see it as ended. Next request
// will reset it
// thrA.setParam(null);
// Next request
inputBuffer.nextRequest();
outputBuffer.nextRequest();
}
rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
// Recycle
inputBuffer.recycle();
outputBuffer.recycle();
this.socket = null;
// Recycle ssl info
sslSupport = null;
}