公司有本《Java网络编程》一直闲置在书架上,反正我对Socket方面不太懂,今天跟着书学习一番。

> 参考的优秀书籍

《Java网络编程》 --中国电力出版社

> 最简单的服务器端

当客户端连接进来,向客户端发送“welcome”以表咋程序员的亲切感~~

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket; public class SimpleServerSocket { public static void main(String[] args) {
ServerSocket ss = null;
Socket s = null;
OutputStreamWriter osw = null;
try {
ss = new ServerSocket(9000); s = ss.accept();
osw = new OutputStreamWriter(s.getOutputStream());
osw.write("welcome..." + System.getProperty("line.separator"));
osw.flush();
System.out.println("outputed."); } catch (IOException e) {
System.out.println("socket exception.");
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
CloseableCloser.close(osw);
CloseableCloser.close(s);
CloseableCloser.close(ss);
}
} }

有许多资源需要关闭,那就写一个小的工具类来关闭吧

import java.io.Closeable;
import java.io.IOException; public class CloseableCloser { public static void close(Closeable c) {
if (c == null) {
return;
} try {
c.close();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("exception when closing.");
e.printStackTrace();
}
} }

通过Linux telnet一下,看到反馈了。

当然用Windows telnet也一样的,只是Windows telnet跳了一个页面,不方便截图而已。

注意:如果服务端输出语句时没有加换行符,我在Linux、Windows测试时都没看到打印welcome哦。

telnet xx.xx.xx.xx 9000
Trying xx.xx.xx.xx...
Connected to xx.xx.xx.xx.
Escape character is '^]'.
welcome...
Connection closed by foreign host.

当然也可通过Java Socket编写客户端去连接

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException; public class SimpleSocket { public static void main(String[] args) {
Socket s = null;
BufferedReader br = null;
String line = null;
try {
s = new Socket("127.0.0.1", 9000);
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
while ((line = br.readLine()) != null) {
System.out.println(line);
} } catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
CloseableCloser.close(s);
} } }

> 提供持续的服务,同时处理好不同的异常

看上面的服务端程序,可以发现它只能处理一个任务,而服务端一般来说是提供持续的服务的嘛,那么我们加一个while true呗。

另外,与客户端交互的Socket的异常和ServerSocket的异常是不是需要分开处理一下呢?试想,你一定不想某一个业务出现异常了,导致整个服务端的服务都中止的。

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket; public class SimpleServerSocket { public static void main(String[] args) {
ServerSocket ss = null;
Socket s = null;
OutputStreamWriter osw = null;
try {
ss = new ServerSocket(9000); while (true) {
try {
s = ss.accept();
osw = new OutputStreamWriter(s.getOutputStream());
osw.write("welcome..." + System.getProperty("line.separator"));
osw.flush();
System.out.println("outputed."); } catch (IOException e) {
System.out.println("socket exception.");
// TODO Auto-generated catch block
e.printStackTrace(); } finally {
CloseableCloser.close(osw);
CloseableCloser.close(s);
}
} } catch (IOException e) {
System.out.println("server socket exception.");
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (ss != null) {
CloseableCloser.close(ss);
}
}
} }

这样,你用多个客户端不断地连接,它都给你响应了。

> 并发地处理任务

上述的服务端代码有一段线程睡眠的代码用于模拟业务处理所需的时间的,我们把它的注解解开,然后用不同客户端连接,可以发现,程序在同一时间只能处理一个任务嘛。

而且,由于服务端同时只能处理一个请求,其他请求就堵塞了,操作系统会将请求同一端口的请求存储在一个先进先出的队列中,然而这个队列有长度限制。当然,这个限制各个操作系统不同。

不信,那么我们用Java多线程发送150个请求:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException; public class MultipleSocket extends Thread { public static void main(String[] args) {
for (int i = 0; i < 150; i++) {
new MultipleSocket().start();
}
} public void run() {
Socket s = null;
BufferedReader br = null;
String line = null;
try {
System.out.println(this.getName() + " is started."); s = new Socket("127.0.0.1", 9000);
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
while ((line = br.readLine()) != null) {
System.out.println(line);
} } catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
CloseableCloser.close(br);
CloseableCloser.close(s);
}
} }

不出意外,将报以下异常:

java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)

那么我们就转为线程处理呗!

这里换为多线程处理,同时限制同时最多处理2个线程(需要限制几个线程数,自己设置哦)。

为什么要限制线程数量呢?如果同时许多了客户端连接,超过一定数量,最直接的结果就是内存耗尽了。

关于如何限制线程数量,可以参考以前的博文:【多线程】并发执行指定数量的线程

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class SimpleServerSocket { public static void main(String[] args) {
ServerSocket ss = null;
Socket s = null;
OutputStreamWriter osw = null;
ExecutorService es = Executors.newFixedThreadPool(2); try {
ss = new ServerSocket(9000); while (true) {
s = ss.accept();
es.execute(new BusinessThread(s));
} } catch (IOException e) {
System.out.println("server socket exception.");
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (ss != null) {
CloseableCloser.close(ss);
}
}
} }
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.concurrent.TimeUnit; public class BusinessThread implements Runnable { Socket s = null; public BusinessThread(Socket s) {
super();
this.s = s;
} public void run() {
OutputStreamWriter osw = null;
try {
osw = new OutputStreamWriter(s.getOutputStream());
osw.write("welcome..." + System.getProperty("line.separator"));
osw.flush();
System.out.println("outputed."); // 模拟这里的业务进行得很慢
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } catch (IOException e) {
System.out.println("socket exception.");
// TODO Auto-generated catch block
e.printStackTrace(); } finally {
CloseableCloser.close(osw);
CloseableCloser.close(s);
}
} }

【Java】ServerSocket的学习笔记的更多相关文章

  1. Java:NIO 学习笔记-3

    Java:NIO 学习笔记-3 根据 黑马程序员 的课程 JAVA通信架构I/O模式,做了相应的笔记 3. JAVA NIO 深入剖析 在讲解利用 NIO 实现通信架构之前,我们需要先来了解一下 NI ...

  2. Java:NIO 学习笔记-2

    Java:NIO 学习笔记-2 上一篇 NIO 学习笔记-1 看了 尚硅谷 的相应教程,此处又对比看了 黑马程序员 的课程 JAVA通信架构I/O模式,做了相应的笔记 前言 在 Java 的软件设计开 ...

  3. Java:NIO 学习笔记-1

    Java:NIO 学习笔记-1 说明:本笔记是根据bilibili上 尚硅谷 的课程 NIO视频 而做的笔记 主要内容 Java NIO 简介 Java NIO 与 IO 的主要区别 缓冲区(Buff ...

  4. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  5. Java多线程技术学习笔记(二)

    目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...

  6. Java安全防御学习笔记V1.0

    Java安全防御学习笔记V1.0http://www.docin.com/p-766808938.html

  7. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  8. java之jvm学习笔记三(Class文件检验器)

    java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...

  9. java之jvm学习笔记五(实践写自己的类装载器)

    java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...

  10. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

随机推荐

  1. 变形--矩阵 matrix()

    matrix() 是一个含六个值的(a,b,c,d,e,f)变换矩阵,用来指定一个2D变换,相当于直接应用一个[a b c d e f]变换矩阵.就是基于水平方向(X轴)和垂直方向(Y轴)重新定位元素 ...

  2. CCF真题之最大矩形

    201312-3 问题描述 在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi.这n个矩形构成了一个直方图.例如,下图中六个矩形的高度就分别是3, 1, 6 ...

  3. docker 批量删除容器

     docker rm `docker ps -a |awk '{print $1}' | grep [0-9a-z]`

  4. mysql 线程池 数据库连接池

    当客户端请求的数据量比较大的时候,使用线程池可以节约大量的系统资源,使得更多的CPU时间和内存可以高效地利用起来.而数据库连接池的使用则将大大提高程序运行效率,同时,我们可以通过其自身的管理机制来监视 ...

  5. 杭电1241 Oil Deposits

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission ...

  6. Java IO总结之缓冲读入文件

    package com.io; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException ...

  7. js对象遍历

    js对象遍历可以使用比较普遍的方法:如下 var ss={aa:"aa",bb:"bb"}; for(var s in ss){ console.info(&q ...

  8. rsync 远程数据同步工具详解

    rysnc 命令用法:(OPTION-参数,USER-用户,HOST-IP地址,SRC-复制源位置,DEST-复制目标位置)Shell拉:rsync [OPTION] [USER@]HOST:SRC ...

  9. 使用jprofiler8远程监控weblogic的配置方法

    jprofiler8的注册码:L-Larry_Lau@163.com#36573-fdkscp15axjj6#25257 未完待续

  10. php的内存分配还是很智能的

    <?php echo memory_get_usage().PHP_EOL;$a = 1;$b = $a;echo memory_get_usage().PHP_EOL; <?php ec ...