一个在本机7777端口提供字符串时间的Socket服务,程序运行后,可以在命令行直接telnet localhost 7777进行测试。
程序虽然简单,但包含了很多相当有用的知识。在程序后面列举了几个我觉得需要注意的地方。(当然还有很多可以讨论地方。)
复杂的东西都是一点一滴建立在简单的模型或者框架上的。所以要想写出很漂亮和健壮的Socket程序,还得从头开始吧。
下面一篇文章我会写一个简单的客户端Socket程序用以和这个ServerSocket交互。
1 只能同时处理一个客户端,想想为什么? @_@
import java.util.Date; public class ClientServer public ClientServer(int port) throws IOException { private void init() throws IOException { public void run() { public int getPort() { public static void main(String[] args) {
while (true) { |
注意点:(不知道有没有理解错误的地方)
1 在这里这个ServerSocket是放在一个后台线程里运行的,所以当主线程(main所在的那个线程)退出时,后台线程也自动中断退出了。这里 通过在main里用Thread.currentThread().sleep(30*1000);让主线程休息30秒来让ServerSocket达到运行30秒的效果,如果要让程序运行1个小时,把sleep里的参数改成(60*60*1000)(单位是毫秒)。(后台线程指无法单独运行的线程)
2 clientSock = this.serverSocket.accept(); 和 System.out.println(reader.readLine());都是阻塞语句 (不知道用这个词语恰不恰当),,正常情况下,只有当条件满足,程序才会继续执行下去。clientSock = this.serverSocket.accept()表示只有当客户端尝试去连接这个ServerSocket的(程序里是本机的7777端口)。程序才会返回一个新Socket用于跟客户端通信。(当然这是正常情况,非正常情况程序也有其他途径返回的,比如抛出异常)。
Accept()应该是ServerSocket最重要的方法了,所以这里列出JDK中的资料供参考
accept public Socket accept() throws IOException 侦听并接受到此套接字的连接。此方法在进行连接之前一直阻塞。 创建新套接字 s,如果存在安全管理器,则使用 s.getInetAddress().getHostAddress() 和 s.getPort() 作为参数调用安全管理器的 checkAccept 方法,以确保允许该操作。这可能会导致 SecurityException 异常。 返回: 新套接字 抛出: IOException - 如果等待连接时发生 I/O 错误。 SecurityException - 如果安全管理器存在并且其 checkListen 方法不允许进行该操作。 SocketTimeoutException - 如果以前使用 setSoTimeout 设置了超时并且已到达超时值。 IllegalBlockingModeException - 如果此套接字具有相关联的通道、通道处于非阻塞模式并且不存在准备接受的连接 另请参见: |
在这里ServerSocket主要是提供时间服务的,所以并不需要客户端响应。这里提供System.out.println(reader.readLine())的语句,只是为了表明服务端跟客户端的
交互是双向的。readLine()也是阻塞语句,正常情况下只有在流中读到行才会正常返回。在JDK文档中BufferdReader的readLine()方法并没有提到是不是阻塞的。
因为readLine()方法的实质只是一个不断的调用read()方法的过程。所以我们再参考下read()方法。(看下面说明),在里面也没有提到阻塞这个概念!
因为BufferedReader的read()的方法是覆盖父类的read()方法,所以也有必要参考下父类Reader的read()方法。在JDK中是这么说明的
读取单个字符。在有可用字符、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。
BufferedReader类 readLine public String readLine() throws IOException 读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('/n')、回车 ('/r') 或回车后直接跟着换行。 返回: 包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null 抛出: IOException - 如果发生 I/O 错误
read public int read() throws IOException 读取单个字符。 覆盖: 返回: 作为范围 0 到 65535 (0x00-0xffff) 的整数读入的字符,如果已到达流末尾,则返回 -1 抛出: IOException - 如果发生 I/O 错误 |
3 因为Socket是有限的系统资源,所以我们在使用完以后应该使用clientSock.close();关闭以便还给系统。
4 PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSock.getOutputStream())));
在这里,其实不用以这么麻烦的形式去往流里仅仅输入字符串形式的时间的,但是以这么优美的语句去书写想要表达的概念确实
一个非常痛快的事情。用最直接,最简洁的语句表达出想要做的事情, 是程序员最喜欢的形式。~~~(本来就是因为有好用的接口,好用的标准库,
直观简洁的代码才喜欢Java.~~~@_@)