前言  

socket(套接字),Socket和ServerSocket位于java.net包中,之前虽然对socket有过一些了解,但一直都是云里雾里的,特意仔细的学习了一个socket,用socket模拟一个天气查询的功能,并且解决了几个使用socket过程中比较严重的问题。

最简单的客户端和服务端

服务端代码

 1 package cn.hucc.socket.server;
 2
 3 import java.io.DataInputStream;
 4 import java.io.DataOutputStream;
 5 import java.io.IOException;
 6 import java.net.ServerSocket;
 7 import java.net.Socket;
 8
 9 /**
10  *
11  * @auth hucc
12  * @date 2015年10月10日
13  */
14 public class WeatherServer {
15
16     private static final int PORT = 8888;
17
18     public static void main(String[] args) {
19
20         ServerSocket server = null;
21         Socket socket = null;
22         DataInputStream dataInputStream = null;
23         DataOutputStream dataOutputStream = null;
24         try {
25             server = new ServerSocket(PORT);
26             System.out.println("天气服务端已经移动,监听端口:" + PORT);
27             socket = server.accept();
28
29             // 接受客户端请求
30             dataInputStream = new DataInputStream(socket.getInputStream());
31             String request = dataInputStream.readUTF();
32             System.out.println("from client..." + request);
33
34             // 响应客户端
35             dataOutputStream = new DataOutputStream(socket.getOutputStream());
36             String response = "天气:晴朗,温度:36度";
37             dataOutputStream.writeUTF(response);
38
39         } catch (IOException e) {
40             e.printStackTrace();
41         } finally {
42             try {
43                 if (dataInputStream != null) {
44                     dataInputStream.close();
45                 }
46                 if (dataOutputStream != null) {
47                     dataOutputStream.close();
48                 }
49             } catch (IOException e) {
50                 e.printStackTrace();
51             }
52         }
53     }
54 }

View Code

服务端代码很简单,这里没有直接使用InputStream和OutputStream两个流,而是使用了DataInputStream和DataOutputStream两个类,通过readUTF()和writeUTF()两个方法免去转码的痛苦。

客户端代码

 1 package cn.hucc.socket.client;
 2
 3 import java.io.DataInputStream;
 4 import java.io.DataOutputStream;
 5 import java.io.IOException;
 6 import java.net.Socket;
 7
 8 /**
 9  *
10  * @auth hucc
11  * @date 2015年10月10日
12  */
13 public class WeatherClient {
14     private static final String HOST = "127.0.0.1";
15     private static final int PORT = 8888;
16
17     public static void main(String[] args) {
18
19         Socket socket = null;
20         DataInputStream dataInputStream = null;
21         DataOutputStream dataOutputStream = null;
22         try {
23             socket = new Socket(HOST, PORT);
24
25             //给服务端发送请求
26             dataOutputStream = new DataOutputStream(socket.getOutputStream());
27             String request = "北京";
28             dataOutputStream.writeUTF(request);
29
30             dataInputStream = new DataInputStream(socket.getInputStream());
31             String response = dataInputStream.readUTF();
32             System.out.println(response);
33
34         } catch (IOException e) {
35             e.printStackTrace();
36         }finally{
37             try {
38                 if(dataInputStream != null){
39                     dataInputStream.close();
40                 }
41                 if(dataOutputStream != null){
42                     dataOutputStream.close();
43                 }
44                 if(socket != null){
45                     socket.close();
46                 }
47             } catch (IOException e) {
48                 e.printStackTrace();
49             }
50
51         }
52     }
53 }

View Code

运行结果

客户端运行结果:

服务端运行结果:

结果分析

客户端和服务端都运行起来了,并且达到了天气查询的效果,但是服务端只服务了一次就停止了,这明显不符合需求,服务端应该响应完客户端之后,继续监听8888端口,等待下一个客户端的连接。

让服务端一直提供服务

将服务端的代码写入死循环中,一直监听客户端的请求。修改服务端的代码:

 1 public static void main(String[] args) throws IOException {
 2
 3         ServerSocket server = null;
 4         Socket socket = null;
 5         DataInputStream dataInputStream = null;
 6         DataOutputStream dataOutputStream = null;
 7         server = new ServerSocket(PORT);
 8         System.out.println("天气服务端已经移动,监听端口:" + PORT);
 9         while(true){
10             try {
11                 socket = server.accept();
12
13                 // 接受客户端请求
14                 dataInputStream = new DataInputStream(socket.getInputStream());
15                 String request = dataInputStream.readUTF();
16                 System.out.println("from client..." + request);
17
18                 // 响应客户端
19                 dataOutputStream = new DataOutputStream(socket.getOutputStream());
20                 String response = "天气:晴朗,温度:36度";
21                 dataOutputStream.writeUTF(response);
22
23             } catch (IOException e) {
24                 e.printStackTrace();
25             } finally {
26                 try {
27                     if (dataInputStream != null) {
28                         dataInputStream.close();
29                     }
30                     if (dataOutputStream != null) {
31                         dataOutputStream.close();
32                     }
33                 } catch (IOException e) {
34                     e.printStackTrace();
35                 }
36             }
37         }
38     }

View Code

通过while(true)死循环,服务端一直监听8888端口,由于socket是阻塞的,只有服务端完成了当前客户端的响应,才会继续处理下一个客户端的响应。这样一直让主线线程去处理socket请求不合适,因此需要为服务端加上多线程功能,同时处理多个socket请求。

给服务端加上多线程

修改代码,将服务端的socket处理抽取出来,并且封装到Runnable接口的run方法中。

 1 package cn.hucc.socket.server;
 2
 3 import java.io.DataInputStream;
 4 import java.io.DataOutputStream;
 5 import java.io.IOException;
 6 import java.net.Socket;
 7
 8 /**
 9  *
10  * @auth hucc
11  * @date 2015年10月10日
12  */
13 public class WeatherThread extends Thread {
14
15     private Socket socket;
16
17     public WeatherThread(Socket socket){
18         this.socket = socket;
19     }
20
21     public void run() {
22
23         DataInputStream dataInputStream = null;
24         DataOutputStream dataOutputStream = null;
25         try {
26             // 接受客户端请求
27             dataInputStream = new DataInputStream(socket.getInputStream());
28             String request = dataInputStream.readUTF();
29             System.out.println("from client..." + request+" 当前线程:"+Thread.currentThread().getName());
30
31             // 响应客户端
32             dataOutputStream = new DataOutputStream(socket.getOutputStream());
33             String response = "天气:晴朗,温度:36度";
34             dataOutputStream.writeUTF(response);
35
36         } catch (IOException e) {
37             e.printStackTrace();
38         } finally {
39             try {
40                 if (dataInputStream != null) {
41                     dataInputStream.close();
42                 }
43                 if (dataOutputStream != null) {
44                     dataOutputStream.close();
45                 }
46             } catch (IOException e) {
47                 e.printStackTrace();
48             }
49         }
50     }
51 }

View Code

修改服务端,添加多线程功能

 1 package cn.hucc.socket.server;
 2
 3 import java.io.IOException;
 4 import java.net.ServerSocket;
 5 import java.net.Socket;
 6
 7 /**
 8  *
 9  * @auth hucc
10  * @date 2015年10月10日
11  */
12 public class WeatherServer {
13
14     private static final int PORT = 8888;
15
16     public static void main(String[] args) throws IOException {
17
18         ServerSocket server = null;
19         Socket socket = null;
20         server = new ServerSocket(PORT);
21         System.out.println("天气服务端已经移动,监听端口:" + PORT);
22         while(true){
23                 socket = server.accept();
24                 new WeatherThread(socket).start();
25         }
26     }
27 }

View Code

此时服务端已经拥有多线程处理能力了,运行结果如下图:

弊端分析

尽管服务端现在已经有了多线程处理能力,但是通过运行结果,我们可以看到,服务端每次接收到客户端的请求后,都会创建一个新的线程去处理,而jvm的线程数量过多是,服务端处理速度会变慢。而且如果并发较高的话,瞬间产生的线程数量也会比较大,因此,我们需要再给服务端加上线程池的功能。

给服务端加上线程池功能

使用java.util.concurrent.Executor类就可以创建一个简单的线程池,代码如下:

 1 package cn.hucc.socket.server;
 2
 3 import java.io.IOException;
 4 import java.net.ServerSocket;
 5 import java.net.Socket;
 6 import java.util.concurrent.Executor;
 7 import java.util.concurrent.Executors;
 8
 9 /**
10  *
11  * @auth hucc
12  * @date 2015年10月10日
13  */
14 public class WeatherServer {
15
16     private static final int PORT = 8888;
17
18     public static void main(String[] args) throws IOException {
19
20         ServerSocket server = null;
21         Socket socket = null;
22         server = new ServerSocket(PORT);
23         System.out.println("天气服务端已经移动,监听端口:" + PORT);
24
25         //FixedThreadPool最多开启3(参数)个线程,多余的线程会存储在队列中,等线程处理完了
26         //再从队列中获取线程继续处理
27         Executor executor = Executors.newFixedThreadPool(3);
28         while(true){
29                 socket = server.accept();
30                 executor.execute(new WeatherThread(socket));
31         }
32     }
33 }

View Code

Executor一共有4种线程池实现,这里使用了FixedThreadPool最多开启3(参数)个线程,多余的线程会存储在队列中,等线程处理完了再从队列中获取,继续处理。这样的话无论并发量多大,服务端只会最多3个线程进行同时处理,使服务端的压力不会那么大。

运行结果:

通过运行结果,可以看到线程只开了1,2,3三个线程。

到这里,socket的简易教程便结束了。O(∩_∩)O~~

转载于:https://www.cnblogs.com/gnoc/p/4866788.html

带线程池的socket客户端与服务端相关推荐

  1. 基于半同步/半反应堆线程池实现的HTTP解析服务端程序

    简介: 半同步/半反应堆线程池是通过一个线程往工作队列添加任务T,然后工作线程竞争工作队列获得任务T.HTTP请求解析服务端程序:逐行解析客户端发送来的HTTP请求然后作出HTTP回答.采用线程池就是 ...

  2. java socket同步_Java socket客户端与服务端同步通信实例

    工作中没涉及有关JAVA SOCKET编程的实际经历,但理论大概了解.想正明一下自已的对JAVA SOCKET理解写个通信TEST,通过TEST验证了基本与理论相近.下面是TEST SRC CODE ...

  3. python客户端和服务端实验_python实现socket客户端和服务端简单示例

    复制代码@H_301_3@ 代码如下: import socket #socket通信客户端 def client(): mysocket=socket.socket(socket.AF_INET,s ...

  4. android studio中使用AIDL进行客户端与服务端互相通信

    前言 在AIDL实现IPC通信,调用远程服务端的方法.但是,远程服务端并不能主动给客户端返回信息.在很多情况下是需要远程服务端主动给客户端返回数据,客户端只需要进行监听即可,这是典型的观察者模式.这篇 ...

  5. 基于Socket实现客户端与服务端通讯

    基于Socket实现客户端与服务端通讯 socket 概述 Socket,套接字就是两台主机之间逻辑连接的端点.TCP/IP协议是传输层协议,主要解决数据如何 在网络中传输,而HTTP是应用层协议,主 ...

  6. java网络编程Socket实现客户端向服务端发送信息

    (可按目录按需阅读,我一般会整理的比较细) 前置知识 java IO Socket 什么是socket?socket字面意思其实就是一个插口或者套接字,包含了源ip地址.源端口.目的ip地址和源端口. ...

  7. php socket 握手,python Socket之客户端和服务端握手详细介绍

    这篇文章主要为大家详细介绍了python Socket之客户端和服务端握手,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 简单的学习下利用socket来建立客户端和服务端之间的连接并且发送数据 1 ...

  8. php winform通信,C# Winform 通过Socket实现客户端和服务端TCP通信

    操作界面如下: 1.声明Socket 第一个参数:寻址方式,第二个参数:传输数据的方式,第三个参数:通信协议 Socket socket = new Socket(AddressFamily.Inte ...

  9. OSI七层、TCP/IP五层、UDP、TCP的socket编程(服务端及客户端)、字节序转换、多进程以及多线程服务端的实现

    1.网络以覆盖范围划分:局域网/城域网/广域网   互联网/因特网   以太网/令牌环网--组网方式 2.在网络中必须能够为一表示每一台主机,才能实现点到点的精确通信            IP地址: ...

最新文章

  1. varnish详解3
  2. Spring事件机制详解
  3. 服务器windows模拟linux环境,科学网—Windows不用虚拟机或双系统,轻松实现shell环境:gitforwindows - 刘永鑫的博文...
  4. leetcode 994.腐烂的橘子
  5. 解决tfs工作区绑定问题
  6. 「深入浅出」主流前端框架更新批处理方式
  7. Android开发在路上:少去踩坑,多走捷径
  8. jQuery:基础知识学习
  9. 如何使用商品历史价格查询网站
  10. android自定义网络请求框架,安卓快速开发框架(十九)XBaseAndroid Http网络请求
  11. vue3.0 watch监听器使用方法
  12. JAVA生成甘特图Excel导出
  13. JVM中栈的frames详解
  14. unity3D修改商店下载路径
  15. Xcode效率提升(快捷键等)
  16. 解决Identify and stop the process that‘s listening on port 8080 端口问题
  17. 根据经纬度,随机生成经纬度
  18. w32time服务自动更新时间(NTP)
  19. ioremap和mmap的区别
  20. 块存储,文件存储,对象存储的区别和理解

热门文章

  1. javascript window alert
  2. Flask Oauth
  3. Flask Middle
  4. matlab中常微分方法,MATLAB解常微分方程组的解法(好东西要共享)
  5. java设置文件为文件夹_如何为文件夹及其所有子文件夹和文件设置chmod? [关闭]...
  6. VCSA6.7 备份和还原
  7. 华为18级工程师三年心血终成趣谈网络协议文档(附大牛讲解)
  8. 使用计算机计算一个多边形,多边形面积计算器
  9. 差分电荷密度 matlab,差分电荷密度
  10. 如何查找cvpr类的论文_美国凯泽大学工商管理硕士:MBA论文案例编写类如何写?...