如何利用websocket访问数据库进行HTTP访问

博客分类:
HTTP服务器核心就是Socket短连接
先简单说概念:
1、socket就是TCP/IP实现的套接字,就是应用层调用下层服务的接口。
2、短连接指的是连接建立后,双方进行数据交互(通常是一个数据包,也可以是多个),交互完毕后立即关闭连接的TCP/IP实现方式就是常说的短连接,最常见的短连接例子就是HTTP协议。
3、长连接则指的是双方交互完毕后,不关闭连接,而让连接一直空闲着等待下一次交互,这样在一次交互前就免去了再重新建立连接的消耗,本机测试一次 socket连接需要耗时23毫秒。
优点就是性能好。缺点有二,一是实现方式比较复杂,需要单独用线程收,发倒是无所谓;二是需要增加链路检测的机制,由于连接在空闲时双方都无法确认对端是否出现异常退出,因为根据TCP/IP,如果连接的一方正常退出,对端都会收到一个信号,而当一方异常退出时,对端是无法收到信号的,这时就会出现 connection reset、connection reset by peer和broken pipe异常。
接下来说说JAVA如何实现短连接。一、先来看发送到方法,这个比较简单。直接获得socket的OutputStream流,然后用write方法,flush方法即可。这里要说明的就是,之前认为使用flush方法在底层就是一个TCP包,其实不然,上层何时按照上面策略封装TCP包上层根本无法知道,经过测试可知,下层封装的TCP包大小与flush无必然联系。这里有个参数可以设置,就是sock.setTcpNoDelay(true),如果设置为true,则对于缓冲区不进行拼接,立即发送。这里涉及nagle算法,用于解决小封包问题,感兴趣的朋友可以自己搜索
热身运动
/**
* 单个文件的HTTP Server,输入本机地址,返回d:/index.html文件
public class SingleFileHttpServer extends Thread {
private byte[]
private byte[]
public SingleFileHttpServer(byte[] data, String encoding, String MIMEType) throws UnsupportedEncodingException {
this.content =
this.port = 80;
String header = "HTTP/1.0 200 OK\r\n" + "Server: OneFile 1.0 \r\n"
+ "Content-length: " + this.content.length
+ "\r\n" + "Content-type: " + MIMEType + "\r\n";
this.header = header.getBytes(encoding);
public void run() {
server = new ServerSocket(port);
System.out.println("Accepting connections on port " + server.getLocalPort());
System.out.println("Data to be sent:");
System.out.write(this.content);
while (true) {
Socket conn =
conn = server.accept();
OutputStream out = conn.getOutputStream();
InputStream in = conn.getInputStream();
StringBuilder request = new StringBuilder();
if ((temp = in.read()) != -1)
request.append((char) temp);
if (request.toString().indexOf("HTTP/") != -1)
out.write(header);
out.write(content);
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
conn.close();
} catch (IOException e) {
throw new RuntimeException(e);
public static void main(String[] args) {
String encoding = "ASCII";
String fileName = "D:/index.html";
String contentType = "text/plain";
if (fileName.endsWith("html") || fileName.endsWith("htm"))
contentType = "text/html";
InputStream in = new FileInputStream(new File(fileName));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((temp = in.read()) != -1)
baos.write(temp);
byte[] data = baos.toByteArray();
SingleFileHttpServer server =
new SingleFileHttpServer(data, encoding, contentType);
server.start();
} catch (FileNotFoundException e) {
} catch (IOException e) {
* 跳转地址,输入本机地址,自动跳转到sina
public class Redirector implements Runnable {
private String siteU
public Redirector(int port, String siteUrl) {
this.port =
this.siteUrl = siteU
public void run() {
ServerSocket server = new ServerSocket(port);
while (true) {
Socket conn = server.accept();
Thread t = new RedirectThread(conn);
t.start();
} catch (IOException e) {
throw new RuntimeException(e);
private class RedirectThread extends Thread {
public RedirectThread(Socket conn) {
this.conn =
public void run() {
Writer out = new OutputStreamWriter(conn.getOutputStream());
Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
while (true) {
temp = in.read();
if (temp == '\r' || temp == '\n' || temp == -1)
sb.append((char) temp);
String request = sb.toString();
int firstSpace = request.indexOf(' ');
int secondSpace = request.indexOf(' ', firstSpace + 1);
String theFile = request.substring(firstSpace + 1, secondSpace);
if (request.indexOf("HTTP") != -1) {
// 这是一个HTTP响应码,告知客户端要被重定向
out.write("HTTP/1.0 302 FOUND\r\n");
// 服务器当前时间
out.write("Date: " + new Date() + "\r\n");
// 服务器的名称和版本【可选的】
out.write("Server: Redirector 1.0\r\n");
// 告知要重定向的位置,浏览器会自动跳转
out.write("Location: " + siteUrl + theFile + "\r\n");
// 指示客户端看到的是HTML,发送一个空行表明结束
out.write("Content-type: text/html\r\n\r\n");
out.flush();
// 有些老浏览器,不支持redirection,我们需要生成HTML说明
out.write("&HTML&&HEAD&&TITLE&Document moved&/TITLE&&/HEAD&\r\n");
out.write("&BODY&&H1&Document moved&/H1&\r\n");
out.write("The document " + theFile + " has moved to\r\n&A HREF=\""
+ siteUrl + theFile + "\"&" + siteUrl + theFile
+ "&/A&.\r\n Please update your bookmarks&P&");
out.write("&/BODY&&/HTML&\r\n");
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (conn != null)
conn.close();
} catch (IOException e) {
throw new RuntimeException(e);
public static void main(String[] args) {
int port = 80;
String siteUrl = ".cn";
Thread server = new Thread(new Redirector(port, siteUrl));
server.start();
* Java版 HTTP服务器
public class JHTTPServer extends Thread {
private File docRootD
private String indexFileN
private ServerS
private int numThread = 50;
public JHTTPServer(File docRootDir) throws IOException {
this(docRootDir, 80, "index.html");
public JHTTPServer(File docRootDir, int port, String indexFileName)
throws IOException {
this.docRootDir = docRootD
this.indexFileName = indexFileN
server = new ServerSocket(port);
public void run() {
for (int i = 0; i & numT i++) {
Thread t = new Thread(new RequestProcessor(docRootDir, indexFileName));
t.start();
System.out.println("Accepting connections on port " + server.getLocalPort());
System.out.println("Document Root: " + docRootDir);
while(true){
Socket conn = server.accept();
RequestProcessor.processRequest(conn);
} catch (IOException e) {
throw new RuntimeException(e);
public static void main(String[] args) {
File docRoot = new File("D:/src/HTML_CSS");
new JHTTPServer(docRoot).start();
} catch (IOException e) {
System.out.println("Server could not start because of an " + e.getClass());
System.out.println(e);
* 服务线程池
public class RequestProcessor implements Runnable {
private static List&Socket& pool = new LinkedList&Socket&();
private File docRootD
private String indexFileN
public RequestProcessor(File docRootDir, String indexFileName) {
if (docRootDir.isFile())
throw new IllegalArgumentException(
"documentRootDirectory must be a directory, not a file");
this.docRootDir = docRootD
this.docRootDir = docRootDir.getCanonicalFile();
} catch (IOException ex) {
this.indexFileName = indexFileN
public static void processRequest(Socket conn) {
synchronized (pool) {
pool.add(pool.size(), conn);
pool.notifyAll();
public void run() {
String root = docRootDir.getPath();
while (true) {
synchronized (pool) {
while (pool.isEmpty()) {
pool.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
conn = pool.remove(0);
OutputStream raw = new BufferedOutputStream(conn.getOutputStream());
Writer out = new OutputStreamWriter(raw);
Reader in = new InputStreamReader(new BufferedInputStream(conn.getInputStream()));
StringBuilder request = new StringBuilder();
while (true) {
c = in.read();
if (c == '\r' || c == '\n')
request.append((char) c);
String get = request.toString();
// 记录请求日志
System.out.println(get);
StringTokenizer st = new StringTokenizer(get);
String method = st.nextToken();
String version = "", fileName, contentT
if (method.equals("GET")) {
fileName = st.nextToken();
if (fileName.endsWith("/"))
fileName += indexFileN
contentType = guessContentTypeFromName(fileName);
if (st.hasMoreTokens())
version = st.nextToken();
File theFile = new File(docRootDir, fileName.substring(1, fileName.length()));
// 不让请求超出文档根目录
if (theFile.canRead() && theFile.getCanonicalPath().startsWith(root)) {
DataInputStream dis = new DataInputStream(
new BufferedInputStream(new FileInputStream(theFile)));
byte[] theData = new byte[(int) theFile.length()];
dis.readFully(theData);
dis.close();
if (version.startsWith("HTTP ")) {
out.write("HTTP/1.0 200 OK\r\n");
out.write("Date" + new Date() + "\r\n");
out.write("Server: JHTTP/1.0\r\n");
out.write("Content-length: " + theData.length + "\r\n");
out.write("Content-type: " + contentType + "\r\n\r\n");
out.flush();
// 发送文件,可能是图片或其它二进制数据,所以使用底层的输出流不是书写器
raw.write(theData);
raw.flush();
} else { // 没有找到文件
if (version.startsWith("HTTP ")) { // send a MIME header
out.write("HTTP/1.0 404 File Not Found\r\n");
Date now = new Date();
out.write("Date: " + now + "\r\n");
out.write("Server: JHTTP/1.0\r\n");
out.write("Content-type: text/html\r\n\r\n");
out.write("&HTML&\r\n");
out.write("&HEAD&&TITLE&File Not Found&/TITLE&\r\n");
out.write("&/HEAD&\r\n");
out.write("&BODY&");
out.write("&H1&HTTP Error 404: File Not Found&/H1&\r\n");
out.write("&/BODY&&/HTML&\r\n");
out.flush();
} else { // method does not equal "GET"
if (version.startsWith("HTTP ")) { // send a MIME header
out.write("HTTP/1.0 501 Not Implemented\r\n");
Date now = new Date();
out.write("Date: " + now + "\r\n");
out.write("Server: JHTTP 1.0\r\n");
out.write("Content-type: text/html\r\n\r\n");
out.write("&HTML&\r\n");
out.write("&HEAD&&TITLE&Not Implemented&/TITLE&\r\n");
out.write("&/HEAD&\r\n");
out.write("&BODY&");
out.write("&H1&HTTP Error 501: Not Implemented&/H1&\r\n");
out.write("&/BODY&&/HTML&\r\n");
out.flush();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
conn.close();
} catch (IOException ex) {}
private String guessContentTypeFromName(String name) {
if (name.endsWith(".html") || name.endsWith(".htm")) {
return "text/html";
} else if (name.endsWith(".txt") || name.endsWith(".java")) {
return "text/plain";
} else if (name.endsWith(".gif")) {
return "image/gif";
} else if (name.endsWith(".class")) {
return "application/octet-stream";
} else if (name.endsWith(".jpg") || name.endsWith(".jpeg")) {
return "image/jpeg";
return "text/plain";
下载次数: 84
浏览: 255260 次
来自: 北京
你确定你测试过batch是没问题的???
Request URL:http://localhost:80 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'平常我们要访问某个URL一般都是通过浏览器进行:提交一个URL请求后,浏览器将请求发向目标服务器或者代理服务器,目标服务器或者代理服务器返回我们所需要的数据,浏览器接收到这些数据后保存成文件并进行显示。
下面我们看看如何自己利用winsock2.h中的接口来实现这个功能?为了简化问题,作以下假设:
通过代理服务器进行HTTP访问,这样就省去了对URL进行DNS解析的步骤,假设代理服务器的地址为:192.168.0.1:808。
这个功能由以下几个部分组成:
1. 如何建立连接?
2. 如何发送请求?
3. 如何接收数据?
4. 如何判断数据接收完成?
下面我们依次来看下这些问题如何解决?
一、如何建立与服务器之间的连接
HTTP基本TCP,所以我们需要与服务器建立连接,然后才能发送数据。
建立连接参考如下函数socket_open:
int&socket_open(int&IP,int&Port,int&type){
SOCKET&socketId;
&struct&sockaddr_in&serv_
&socketId=socket(AF_INET,SOCK_STREAM,0);
&if((int)socketId&0)
&&&&&&&printf("[ERROR]Create&a&socket&failed!\n");
&&&&&&&return&-1;
&memset(&serv_addr,0,sizeof(serv_addr));
&serv_addr.sin_family=AF_INET;
&serv_addr.sin_addr.s_addr&=&ntohl(IP);&
&serv_addr.sin_port&=&htons((USHORT)Port);
&status=connect(socketId,(struct&sockaddr*)&serv_addr,sizeof(serv_addr));
&&&&if(status!=0)
&&&&printf("[ERROR]Connecting&failed!\n");&
&&&&closesocket(socketId);
&&&&return&-1;
&return&socketId;
调用方式如下:
int socketId=socket_open(0xC0A); //0xC0A88.0.1的十六进制写法。
二、如何发送请求
发送数据要根据HTTP协议的要求附加协议头:
static&const&char*&protocolHead="GET&/index.html&HTTP/1.1\n"
&&&&&"Accept:&image/gif,&image/x-xbitmap,&image/jpeg,&image/pjpeg,&application/x-shockwave-
flash,&application/vnd.ms-excel,&application/vnd.ms-powerpoint,&application/msword,
&&&&&"Accept-Language:&zh-cn\n"
&&&&&"User-Agent:iPanelBrowser/2.0\n"
&&&&&"Host:&:80\n"
&&&&&"Connection:&close\n\n"
这里使用GET来获取指定URL的指定文档。
建立连接后使用send将这些数据发送出去:
send(socketId, protocolHead,strlen(protocolHead),0);
发送完成HTTP请求后就等待接收数据。
三、如何接收数据
这里采用select循环查询的方式来判断有无数据到来:
struct&timeval&tm&=&{0,7};
&&&&&fd_set&fds_r;
&&&&&char&recvBuf[4096]={‘\0’};
&&&&&FD_ZERO(&fds_r);
&&&&&FD_SET(socketId,&fds_r);
status=select(socketId+&1,&&fds_r,&0,&0,&tm);&
&&&&&if(status&&&0&&&&FD_ISSET(socketId,&&fds_r))
&&&&&&&&&printf("Socket&is&readable...fd=[%d]\n",socketId);
&&&&&&&&&&recv(socketId,recvBuf,4096,0);
这样数据包就保存到缓冲区中了。
四、如何判断数据接收完成
首先对返回数据的状态进行判断,仅当状态为“ HTTP 200 OK ”时才表明正确返回,这时才对数据进行解析并保存,如果状态为HTTP 404 NOT FOUND或者其它状态则表明没有找到资源或者出现其它问题,可参考HTTP 1.1状态代码及其含义。当数据正确返回时,为了将实际数据从协议中分离出来进行保存,需要对HTTP数据包进行解析得到Content-Length,然后在包含Content-Length的当前数据包或者随后的数据包中查找第一个空行,这就是内容(Content)的开始位置,再配合前面解析得到的Content-Length,就能够知道什么时候数据接收完成了。换行符为“\r\n”,也兼容“\n”或者“\r”,设换行符为^P,则空行如果位于内容中间或结尾则可查找“^P^P”,若位于开头,则查找^P。
基本就是上面这些,这四个问题解决了,那么整个问题也就解决了!
文章出处:
阅读(...) 评论()查看: 1319|回复: 8
注册时间最后登录阅读权限200积分4658精华9帖子
原帖地址:
如何利用socket进行HTTP访问平常我们要访问某个URL一般都是通过浏览器进行:提交一个URL请求后,浏览器将请求发向目标服务器或者代理服务器,目标服务器或者代理服务器返回我们所需要的数据,浏览器接收到这些数据后保存成文件并进行显示。
下面我们看看如何自己利用winsock2.h中的接口来实现这个功能?为了简化问题,作以下假设:
通过代理服务器进行HTTP访问,这样就省去了对URL进行DNS解析的步骤,假设代理服务器的地址为:192.168.0.1:808。
这个功能由以下几个部分组成:
1. 如何建立连接?
2. 如何发送请求?
3. 如何接收数据?
4. 如何判断数据接收完成?
下面我们依次来看下这些问题如何解决?
一、如何建立与服务器之间的连接
HTTP基本TCP,所以我们需要与服务器建立连接,然后才能发送数据。
建立连接参考如下函数socket_open:
*打开Socket,返回socketId,-1表示失败
int socket_open(int IP,int Port,int type){
SOCKET socketId; struct sockaddr_in serv_&&int
socketId=socket(AF_INET,SOCK_STREAM,0);
if((int)socketId&0) {& && & printf(&[ERROR]Create a socket failed!/n&);& && & return -1; }
memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family=AF_INET; serv_addr.sin_addr.s_addr = ntohl(IP); serv_addr.sin_port = htons((USHORT)Port); status=connect(socketId,(struct sockaddr*)&serv_addr,sizeof(serv_addr));& & if(status!=0) {& & printf(&[ERROR]Connecting failed!/n&);& & closesocket(socketId);& & return -1; } return socketId;
调用方式如下:
int socketId=socket_open(0xC0A); //0xC0A80001是192.168.0.1的十六进制写法。
注册时间最后登录阅读权限200积分4658精华9帖子
本帖最后由 在线疯狂 于
12:58 编辑
二、如何发送请求
发送数据要根据HTTP协议的要求附加协议头:
static const char* protocolHead=&GET
HTTP/1.1/n&& &&&&Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*/n&& &&&&Accept-Language: zh-cn/n&& &&&&User-Agent:iPanelBrowser/2.0/n&& &&&&Host: && &&&&Connection: close/n/n&
这里使用GET来获取指定URL的指定文档。
建立连接后使用send将这些数据发送出去:
& &&&send(socketId, protocolHead,strlen(protocolHead),0);
发送完成HTTP请求后就等待接收数据。
三、如何接收数据
这里采用select循环查询的方式来判断有无数据到来:
struct timeval tm = {0,7};& &&&fd_set fds_r;& &&&int& &&&char recvBuf[4096]={‘/0’};& &&&FD_ZERO(&fds_r);& &&&FD_SET(socketId,&fds_r);
status=select(socketId+ 1, &fds_r, 0, 0, &tm); //socketId在这里是最大的fd
& &&&if(status & 0 && FD_ISSET(socketId, &fds_r)){& && && &printf(&Socket is readable...fd=[%d]/n&,socketId);& && && & recv(socketId,recvBuf,4096,0);}
这样数据包就保存到缓冲区中了。
四、如何判断数据接收完成
首先对返回数据的状态进行判断,仅当状态为“ HTTP 200 OK ”时才表明正确返回,这时才对数据进行解析并保存,如果状态为HTTP 404 NOT FOUND或者其它状态则表明没有找到资源或者出现其它问题,可参考。
当数据正确返回时,为了将实际数据从协议中分离出来进行保存,需要对HTTP[si
注册时间最后登录阅读权限200积分4658精华9帖子
需要对HTTP数据包进行解析得到Content-Length,然后在包含Content-Length的当前数据包或者随后的数据包中查找第一个空行,这就是内容(Content)的开始位置,再配合前面解析得到的Content-Length,就能够知道什么时候数据接收完成了。换行符为“/r/n”,也兼容“/n”或者“/r”,设换行符为^P,则空行如果位于内容中间或结尾则可查找“^P^P”,若位于开头,则查找^P。
基本就是上面这些,这四个问题解决了,那么整个问题也就解决了!
注册时间最后登录阅读权限200积分14664精华5帖子
感谢楼主分享!
注册时间最后登录阅读权限200积分4658精华9帖子
zhaixiaohu 发表于
感谢楼主分享!
拿来主义,hohoho
注册时间最后登录阅读权限200积分3765精华2帖子
Linux & PHP
不错,感谢分享!
注册时间最后登录阅读权限200积分4658精华9帖子
Xidorn 发表于
不错,感谢分享!
嘿嘿嘿嘿。
注册时间最后登录阅读权限200积分50359精华0帖子
技术总监, 积分 50359, 距离下一级还需 29641 积分
Powered by如何把http请求得到的信息及时的用socket.io发送给其他人? - CNode技术社区
这家伙很懒,什么个性签名都没有留下。
app.get('/info',function(req,res){
var info = ;
io.sockets.on('connection', function (socket){
socket.broadcast.emit('public message', info);
需求:A和B是两个NodejsServer,A请求B的/info并提交一个值info,B怎么把这个info的内容通过socket发送给其他所有人?并且A每请求一次socket就广播一次?
我想到的有两种解决方案:
一、把infor先放到一个全局变量里,然后socket去读取,但是这样的话socket得不断监听info值的变化,这样有一些性能浪费,并且可能会不及时,代码如下:
var info =
app.get('/info',function(req,res){
io.sockets.on('connection', function (socket){
setInterval(&a();&,delaytime);
function a(){
socket.broadcast.emit('public message', info);
二、A用socket去连接B这样的话就可以把A当作socket的一个客户端了,代码:
io.sockets.on('connection', function (socket){
socket.on('ServerB',function(msg){
socket.broadcast.emit('public message', msg);
第二种方案不知道有哪些第三方的Server-to-Server的模块可用。
大家有什么好的解决方案,不妨说来听听啊?
const redis = require('redis');
const redis_obj = redis.createClient(),
msg_sender = redis.createClient();
redis_obj.on(&message&, function(t_id, message)
console.log('send one message to ' + t_id );
socket.emit('message', message);
redis有这样的监听数据set的事件,mongodb不知道有木有呢?
CNode 社区为国内最专业的 Node.js 开源技术社区,致力于 Node.js 的技术研究。
服务器赞助商为
,存储赞助商为
,由提供应用性能服务。
新手搭建 Node.js 服务器,推荐使用无需备案的

我要回帖

更多关于 socket访问外网 的文章

 

随机推荐