【Java】ServerSocket的学习笔记
公司有本《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的学习笔记的更多相关文章
- Java:NIO 学习笔记-3
Java:NIO 学习笔记-3 根据 黑马程序员 的课程 JAVA通信架构I/O模式,做了相应的笔记 3. JAVA NIO 深入剖析 在讲解利用 NIO 实现通信架构之前,我们需要先来了解一下 NI ...
- Java:NIO 学习笔记-2
Java:NIO 学习笔记-2 上一篇 NIO 学习笔记-1 看了 尚硅谷 的相应教程,此处又对比看了 黑马程序员 的课程 JAVA通信架构I/O模式,做了相应的笔记 前言 在 Java 的软件设计开 ...
- Java:NIO 学习笔记-1
Java:NIO 学习笔记-1 说明:本笔记是根据bilibili上 尚硅谷 的课程 NIO视频 而做的笔记 主要内容 Java NIO 简介 Java NIO 与 IO 的主要区别 缓冲区(Buff ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- Java多线程技术学习笔记(二)
目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和w ...
- Java安全防御学习笔记V1.0
Java安全防御学习笔记V1.0http://www.docin.com/p-766808938.html
- java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...
- java之jvm学习笔记三(Class文件检验器)
java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...
- java之jvm学习笔记五(实践写自己的类装载器)
java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...
- java之jvm学习笔记四(安全管理器)
java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...
随机推荐
- linux第4天 shell socket
$[ ] 表示形式告诉shell对方括号中的表达式求值 echo $[3+9] 赋值运算符 =,+=,-=,*=,/=,%=,&=,^=.|=,<<=,>>= let ...
- 经过本人 6 年.net 工作经验证明 .net 工资确实比 Java 低
很久没有逛博客园了,很久没有出来吐槽了.怎么呢?生活压力大,就需要找地方吐槽. 排版不怎么好,文笔不怎么好,可以看出我不是雇佣的写手. 工作到今夏,已经有6个年头了,一直使用着.net技术,但是最近工 ...
- mysql 导出过长的数字列时变科学计数法问题解决办法
--mysql 导出数据时, 数字类型的列如果位数过长,变为科学技术发问题 concat('\t',a.IDCARD_NO) 例子: select concat('\t',a.IDCA ...
- EBS常用小常识(转)
值集: 1.编辑信息:取上一个值集所选的数据.(值集关联) WHERE BANK_ACCOUNT_ID = :$FLEX$.CE_BANK_ACCOUNT_NUM_NAME ORDER BY STAT ...
- qsort函数用法(转)
qsort函数用法 qsort 功 能: 使用快速排序例程进行排序 用 法: void qsort(void *base, int nelem, int width, int (*fcmp)(c ...
- C# 语音识别
利用微软操作系统自动的语音识别功能,读取信息. 1. 在项目中添加 "" 引用 2. 引入命名空间: using SpeechLib; 3. 读取的代码: Spee ...
- 在Asp.Net的Global.asax中Application_Error跳转到自定义错误页无效的解决办法
在开发Asp.Net系统的时候,我们很多时候希望系统发生错误后能够跳转到一个自定义的错误页面,于是我们经常会在Global.asax中的Application_Error方法中使用Response.R ...
- EXCEL 删除重复项并保留最大最小值
自定义排序 框选需要主次排序的区域 开始—排序和筛选—自定义排序 添加筛选条件 若要获取最小值则次要关键字选择升序 排序后的数据 删除重复项 数据—删除重复项 选择要删除的列 删除A列的重复项后,B列 ...
- 什么是BI(Business Intelligence)【转】
谈谈对BI的理解,从BI的定义.基本技术.专业名词.实例应用及扩展等方面进行重新描述,巩固对BI的理解. 一.BI的定义 BI是Business Intelligence的英文缩写,中文解释为商务智能 ...
- Test Android with QTP
by Yaron Assa I have recently come across a plug-in to QTP that enables to automate tests on Android ...