公司有本《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. Fresco源码解析 - DataSource怎样存储数据

    Fresco源码解析 - DataSource怎样存储数据 datasource是一个独立的 package,与FB导入的guava包都在同一个工程内 - fbcore. datasource的类关系 ...

  2. iphone设置铃声

    iphone同步铃声 1.下载itunes 2.打开itunes.文件->将文件添加到资料库...选择一首歌曲加进去 3.右击新加的歌曲,显示简介->选项.调整结束开始时间.不得超过40秒 ...

  3. ThinkPHP讲解(四)——视图

    本次讲解主要以<ThinkPHP开发手册>中“模板”一章中讲解为主 在MainController.class.php中新建一个操作方法Test() namespace Home\Cont ...

  4. linux更新系统之后,删除多余的开机启动项

    实验环境是centos7,采用uefi的引导方式,启动管理软件是grub2 1. 进入 /boot 目录,应该可以发现许多文件的文件名是以 vmlinuz 开头,后面跟着版本信息,这些就是内核.我们要 ...

  5. s3c2440 lcd 显示图片裸机程序

    因为前面的裸机程序非常的简单,就不写博了. 程序的流程: 1,初始化C SP 2,关看门狗 3,初始化SDRAM 4,读出 NAND FLASH 中的 包含图片的程式放到SDRAM里面 5,跳转到SD ...

  6. 搬瓦工的ShadowSock设置方法:

  7. javaWeb 使用jsp标签进行防盗链

    /** * 1.新建类继承SimpleTagSupport * 新建2个属性, 添加对应的set方法 * 覆盖doTag()方法 */ import java.io.IOException; impo ...

  8. Linux MTD系统剖析【转】

    转自:http://blog.csdn.net/lwj103862095/article/details/21545791 版权声明:本文为博主原创文章,未经博主允许不得转载. MTD,Memory ...

  9. spring命名空间不需要版本号

    为什么dubbo启动没有问题? 这篇blog源于一个疑问: 我们公司使了阿里的dubbo,但是阿里的开源网站http://code.alibabatech.com,挂掉有好几个月了,为什么我们的应用启 ...

  10. iOS 开发 证书总结 开发证书和生产证书的区别

    IOS开发 证书总结 开发者证书   ------>>  开发证书是你在真机推送时 用得, 生产证书是app 上架之后 推送给用户用的 首先你必须获得apple开发者证书,上图这个文件就是 ...