Tomcat与Socket关系


本文链接: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;
}

posted @ 2019-10-15 15:37  Zzzwww  阅读(4125)  评论(1编辑  收藏  举报
/* 看板娘 */