导语

仅仅只有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的介绍的更多相关文章

  1. TCP 通信

    一.TCP与UDP的区别 二.ServerSocket与Socket 1 ServerSocket 以上介绍的几个构造方法中,第二个构造方法最常用. 2.Socket import java.io.* ...

  2. Java ServerSocket的服务端代码介绍

    转自:http://developer.51cto.com/art/201003/190007.htm 所谓Java ServerSocket通常也称作"套接字",有不少的时候需要 ...

  3. python select网络编程详细介绍

    刚看了反应堆模式的原理,特意复习了socket编程,本文主要介绍python的基本socket使用和select使用,主要用于了解socket通信过程 一.socket模块 socket - Low- ...

  4. SSL介绍与Java实例

    有关SSL的原理和介绍在网上已经有不少,对于Java下使用keytool生成证书,配置SSL通信的教程也非常多.但如果我们不能够亲自动手做一个SSL Sever和SSL Client,可能就永远也不能 ...

  5. PhoneGap 在 Android 上的插件开发方法介绍

    移动应用开发已经成为软件开发的一个重要方向,但是移动开发面临的一个重要问题就是跨平台的问题.PhoneGap 作为一个多平台的软件开发框架,提供了一次编写多个平台的运行.目前已经支持多达 6 个移动平 ...

  6. 【转】Android bluetooth介绍(二): android blueZ蓝牙代码架构及其uart 到rfcomm流程

    原文网址:http://blog.sina.com.cn/s/blog_602c72c50102uzoj.html 关键词:蓝牙blueZ  UART  HCI_UART H4  HCI  L2CAP ...

  7. Java 语言中 Enum 类型的使用介绍

    Enum 类型的介绍 枚举类型(Enumerated Type) 很早就出现在编程语言中,它被用来将一组类似的值包含到一种类型当中.而这种枚举类型的名称则会被定义成独一无二的类型描述符,在这一点上和常 ...

  8. Java[4] Jetty工作原理介绍(转)

    转自:https://www.ibm.com/developerworks/cn/java/j-lo-jetty/ Jetty 的工作原理以及与 Tomcat 的比较 Jetty 应该是目前最活跃也是 ...

  9. Socket介绍

    一 socket协议 Socket协议的形象描述 socket的英文原义是“孔”或“插座”.在这里作为4BDS UNIX的进程通信机制,取后一种意思.socket非常类似于电话插座.以一个国家级电话网 ...

随机推荐

  1. 数据库进阶之路(五) - MySQL行锁深入研究

    由于业务逻辑的需要,必须对数据表的一行或多行加入行锁,举个最简单的例子,图书借阅系统:假设id=1的这本书库存为1,但是有2个人同时来借这本书,此处的逻辑为: ; --如果restnum大于0,执行u ...

  2. Objective-c粒子动画

    前面贴过几篇关于SpriteKit的案例文章,其中涉及到的动画都是材质类的图片切换或则常规的动画效果,没涉及到今天要说的粒子动画,今天说的粒子动画就是在游戏中实现更佳炫酷的效果必须使用的类,OC中粒子 ...

  3. 3种方法快速制作tpk文件 [转]

    tpk是ArcGIS10.1推出的一种新的数据文件类型,主要是用于将切片文件打包形成离线地图包,tpk可以在ArcGIS Runtime或者ArcGIS for Android/iOS中作为切片底图被 ...

  4. 国外远控软件DarkComet-RAT

    下载地址:[点此下载] 使用步骤: 注册noip.org账号创建主机地址. 安装并配置DUC. 配置监听端口 配置NO-IP Updater 然后点击Update ,配置成功则会提示Success. ...

  5. [转] IIS配置文件的XML格式不正确 applicationHost.config崩溃 恢复解决办法

    IIS配置文件的XML格式不正确 applicationHost.config崩溃 恢复解决办法 源文件:http://www.cnblogs.com/yuejin/p/3385584.html   ...

  6. Dynamics CRM 2011-RootComponent Type

    笔者因为时不时要导出solution,对solution xml进行处理,所以把xml中的rootcomponent type列一下  Type Description 1 Entity 2 Attr ...

  7. Scala override

    var 变量不能在子类中重写,除非父类是抽象类 在抽象类中var变量不能赋初值 abstract class Person{ val name="" def name1=" ...

  8. 使用IdleTest进行TDD单元测试驱动开发演练(2)

    [前言] 1. 有关上篇请参见<使用IdleTest进行TDD单元测试驱动开发演练(1)>,有关本篇用到Entity Framework Code First请参见<使用NuGet助 ...

  9. Java中使用IO流实现大文件的分裂与合并

    文件分割应该算一个比较实用的功能,举例子说明吧比如说:你有一个3G的文件要从一台电脑Copy到另一台电脑, 但是你的存储设备(比如SD卡)只有1G ,这个时候就可以把这个文件切割成3个1G的文件 ,分 ...

  10. commit(), commitNow()和commitAllowingStateLoss()

    关于FragmentTransaction的各种提交方法: commit(),commitAllowingStateLoss(),commitNow()和commitNowAllowingStateL ...