公司有本《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. JAVA实现File类中的遍历操作并输出内容

    package shb.java.testIo; import java.io.BufferedReader; import java.io.BufferedWriter; import java.i ...

  2. sql查询 所有被锁定的表

    --sql查询  所有被锁定的表 select request_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableName ...

  3. -XX:+PrintHeapAtGC 每次一次GC后,都打印堆信息

    -XX:+PrintHeapAtGC每次一次GC后,都打印堆信息 {Heap before GC invocations=0 (full 0): def new generation   total ...

  4. archlinux 网络配置

    https://wiki.archlinux.org/index.php/Network_configuration_%28%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87%2 ...

  5. js表单提交一种方式

    在一个html和php混编的文件中,用到js提交表单的方法: 定义表单id为form1,提交按钮type为submit, var data_info = document.getElementById ...

  6. cvCreateImage函数说明(转载)

    cvCreateImage是openCV中的一个函数.OpenCV是Intel公司支持的开源计算机视觉库. cvCreateImage:创建首地址并分配存储空间    IplImage* cvCrea ...

  7. NOIP200407合唱队形+最长上升子序列O(n^2)详解

    合唱队形解题报告 2016-05-12   4:30——6:45 NOIP200407合唱队形 难度级别:A: 运行时间限制:1000ms: 运行空间限制:256000KB: 代码长度限制:20000 ...

  8. DIV怎样能够垂直居中

    这里只说固定宽高的情况: 1.Top:50%; 2.margin-top:-(height/2); 就这样. 不过很好奇有没有v-align之类的属性可以直接实现.

  9. 前端控制器DispatcherServlet 详解

    DispatcherServlet 是前端控制器设计模式的实现,提供 Spring Web MVC 的集中访问点,而且负责职责的分派,而且与 Spring IoC 容器无缝集成,从而可以获得 Spri ...

  10. 关于IE6/7的 inline-block

    今天在写代码的时候使用了inline-block,但是很意外的在IE6/7下此属性不给力~~ 但是由于我既需要他是个内联数据,又要设置它的宽度设置block,所以只能使用inline-block. 所 ...