ServerSocket的介绍
导语
仅仅只有Socket类是不足以编写服务器的。要创建一个Socket,你需要知道希望连接哪个Internet主机。编写服务器程序时,无法预先了解哪个主机会联系你,即使确实知道,你也不清楚那个主机希望何时与你联系。对于服务器端的Socket,java提供了一个ServerSocket类表示服务器Socket。从技术上讲,服务器Socket在服务器上运行,监听入站TCP连接,每个服务器Socket监听服务器机器上的一个特定端口。当有个客户端尝试连接这个端口时,服务器就被唤醒,协商建立客户端和服务器之间的连接,并返回一个常规的Socket对象,表示两台主机之间的Socket。换句话说,服务器等待连接,客户端发起连接,一旦ServerSocket建立了连接,服务器会使用一个常规的Socket对象向客户端发送数据。
使用ServerSocket
ServerSocket类包含了服务器端Socket所需的全部内容。其中包括构造ServerSocket对象,指定端口监听连接的方法,配置各个服务器Socket选项的方法,以及其它一些常见的方法。下面是服务器程序的基本生命周期:
- 使用一个ServerSocket()构造函数在一个特定端口创建一个新的ServerSocket
- ServerSocket使用其accept()方法监听这个端口的入站连接。accept()会一直阻塞,直到一个客户端尝试建立连接,此时accept()将会返回一个连接客户端和服务器的Socket对象
- 根据服务器的类型,会调用Socket的getInputSteam()方法或getOutputSteam()方法,或者这两个方法都调用,以获得与客户端通信的输入和输出流
- 服务器和客户端根据已协商的协议交互
- 服务器或客户端关闭连接
- 服务器返回到步骤2,等待下一次连接
简单的daytime服务器
public static void main(String[] args) {
try (ServerSocket server = new ServerSocket(13)) {
while (true) {
try (Socket conn = server.accept()) {
Writer out = new OutputStreamWriter(conn.getOutputStream());
out.write(new Date().toString());
out.flush();
out.close();
conn.close();
} catch (IOException e) {}
}
} catch (IOException e) {
e.printStackTrace();
}
}
多线程服务器
操作系统会把指向某个特定端口的入站连接请求存储在一个先进先出的队列中。默认地,Java会将这个队列的长度设置为50,但不同的操作系统会有所不同。有些操作系统有一个最大队列长度,例如,在FreeBSD上,默认的最大队列长度为128。在构建ServerSocket时可以指定这个值,但是这个值不能超过操作系统设置的值。当队列中的连接达到最大容量时,主机会拒绝这个端口上额外的连接,直到队列腾出新的位置为止。为了尽快能够处理队列中的连接,可以采用多线程的方式来处理每个socket。
package com.dy.xidian;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class PooledDaytimeServer {
private final static int PORT = 13;
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(50);
try (ServerSocket server = new ServerSocket(PORT)) {
while (true) {
try {
Socket conn = server.accept();
pool.execute(new DaytimeTask(conn));
} catch (IOException e) {}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class DaytimeTask implements Runnable {
public Socket conn;
public DaytimeTask(Socket _conn) {
conn = _conn;
}
@Override
public void run() {
try {
Writer out = new OutputStreamWriter(conn.getOutputStream());
out.write(new Date().toString());
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (conn != null)
try {
conn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
从客户端读取数据
echo协议是最简单的交互式TCP服务之一。客户端打开指向echo服务器端口7的socket,并发送数据。服务器将数据发回。这个过程一直继续,直到客户端关闭连接为止。echo协议很有用,可以测试网络,确保数据没有被有问题的路由器或防火墙所破坏。下面的代码中使用NIO中的技术,如果对NIO不了解请移步
package com.dy.xidian;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class PooledDaytimeServer {
private final static int PORT = 7;
public static void main(String[] args) {
ServerSocketChannel serverChannel;
Selector selector;
try {
serverChannel = ServerSocketChannel.open();
ServerSocket server = serverChannel.socket();
InetSocketAddress address = new InetSocketAddress(PORT);
server.bind(address);
serverChannel.configureBlocking(false);
selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
return;
}
while (true) {
try {
selector.select();
} catch (IOException e) {
e.printStackTrace();
break;
}
Set<SelectionKey> readyKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
try {
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
System.out.println("Accepted connection from " + client);
client.configureBlocking(false);
SelectionKey clientKey = client.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ);
ByteBuffer buffer = ByteBuffer.allocate(100);
clientKey.attach(buffer);
}
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer output = (ByteBuffer) key.attachment();
client.read(output);
}
if (key.isWritable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer output = (ByteBuffer) key.attachment();
output.flip();
client.write(output);
output.compact();
}
} catch (IOException e) {
key.cancel();
try {
key.channel().close();
} catch (IOException e1) {}
}
}
}
}
}
关闭服务器Socket
使用完一个服务器Socket,就应该将其关闭。但不要把关闭ServerSocket与关闭Socket混淆。关闭ServerSocket会释放本地主机的一个端口,允许另一个服务可以绑定这个端口,并且它还会中断该ServerSocket已经接受的目前处于打开状态的所有Socket。关闭ServerSocket基本使用下面的流程:
ServerSocket server = null;
try {
server = new ServerSocket(port);
} finally {
if (server != null) {
try {
server.close();
} catch (IOException e) {}
}
}
构造服务器Socket
创建一个Socket监听80端口
ServerSocket httpd = new ServerSocket(80);
如果主机上有多个IP地址,我们只想监听特定的IP地址上请求(50表示入栈连接的最大个数)
InetAddress local = InetAddress.getByName("192.168.0.100");
ServerSocket httpd = new ServerSocket(80, 50, local);
ServerSocket的介绍的更多相关文章
- TCP 通信
一.TCP与UDP的区别 二.ServerSocket与Socket 1 ServerSocket 以上介绍的几个构造方法中,第二个构造方法最常用. 2.Socket import java.io.* ...
- Java ServerSocket的服务端代码介绍
转自:http://developer.51cto.com/art/201003/190007.htm 所谓Java ServerSocket通常也称作"套接字",有不少的时候需要 ...
- python select网络编程详细介绍
刚看了反应堆模式的原理,特意复习了socket编程,本文主要介绍python的基本socket使用和select使用,主要用于了解socket通信过程 一.socket模块 socket - Low- ...
- SSL介绍与Java实例
有关SSL的原理和介绍在网上已经有不少,对于Java下使用keytool生成证书,配置SSL通信的教程也非常多.但如果我们不能够亲自动手做一个SSL Sever和SSL Client,可能就永远也不能 ...
- PhoneGap 在 Android 上的插件开发方法介绍
移动应用开发已经成为软件开发的一个重要方向,但是移动开发面临的一个重要问题就是跨平台的问题.PhoneGap 作为一个多平台的软件开发框架,提供了一次编写多个平台的运行.目前已经支持多达 6 个移动平 ...
- 【转】Android bluetooth介绍(二): android blueZ蓝牙代码架构及其uart 到rfcomm流程
原文网址:http://blog.sina.com.cn/s/blog_602c72c50102uzoj.html 关键词:蓝牙blueZ UART HCI_UART H4 HCI L2CAP ...
- Java 语言中 Enum 类型的使用介绍
Enum 类型的介绍 枚举类型(Enumerated Type) 很早就出现在编程语言中,它被用来将一组类似的值包含到一种类型当中.而这种枚举类型的名称则会被定义成独一无二的类型描述符,在这一点上和常 ...
- Java[4] Jetty工作原理介绍(转)
转自:https://www.ibm.com/developerworks/cn/java/j-lo-jetty/ Jetty 的工作原理以及与 Tomcat 的比较 Jetty 应该是目前最活跃也是 ...
- Socket介绍
一 socket协议 Socket协议的形象描述 socket的英文原义是“孔”或“插座”.在这里作为4BDS UNIX的进程通信机制,取后一种意思.socket非常类似于电话插座.以一个国家级电话网 ...
随机推荐
- 简单实用的进度条加载组件loader.js
本文提供一个简单的方法实现一个流程的进度条加载效果,以便在页面中可以通过它来更好地反馈耗时任务的完成进度.要实现这个功能,首先要考虑怎样实现一个静态的进度条效果,类似下面这样的: 这个倒是比较简单,两 ...
- 基于Metronic的Bootstrap开发框架经验总结(14)--条码和二维码的生成及打印处理
在很多项目里面,对条形码和二维码的生成和打印也是一种很常见的操作,在Web项目里面,我们可以利用JS生成条形码和二维码的组件有很多.本文引入两个比较广泛使用的JS组件,用来处理条形码和二维码的生成处理 ...
- Entity Framework 教程——什么是Entity Framework
什么是Entity Framework 编写和管理ADO.NET是一个繁琐而又无聊的工作.微软为你的应用提供了一个名为"Entity Framework"的ORM框架来自动化管理你 ...
- Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等)
Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等) 子查询 描述:查询订单数超过5的顾客信息 查询句法: var 子查询 = from c i ...
- Be a new gentlemen
学好技术的同时,更要注重自身素养的提升! 一 .有则改之,无责加冕 1.女士优先 2. 不随地吐痰, 不乱扔垃圾, 不在人群中抽烟 3. 不大声喧哗 4. 不插队,碰到别人要说抱歉 5. 不在公共交 ...
- js的命名规范
js的命名规范 1.驼峰命名法:首字母是小写的,接下来的字母都以大写字符开头.例如: var testValue = 0; var oneValue = 10; 2. ...
- 航旅事业群面试(li)
一.JVM 1.如何观察垃圾回收? 2.JAVA应用的JVM参数调优? 3.举例说明你所知道的JVM profile方法? 4.GC tunning实战.假如你是一个大型网站的总架构师,有次web应用 ...
- jvm内存区域
概述 jvm内存分为几个区域: 程序计数器 虚拟机栈 本地方法栈 堆 方法区 运行时常量池 直接内存 这些内存区域是在java进程中细分的,为java程序提供服务 不同的区域存储的内容不一样,生命周期 ...
- html标签学习
1. 标题 : <h1> - <h6> 2. 分割线 : <hr> 3. 加粗: <strong> 4. 斜体: <em> <i> ...
- javascript代码 调试方法
你的代码可能包含语法错误,逻辑错误,如果没有调试工具,这些错误比较难于发现. 通常,如果 JavaScript 出现错误,是不会有提示信息,这样你就无法找到代码错误的位置. 在程序代码中寻找错误叫做代 ...