java网络socket编程(三)之ServerSocket服务器端
2016-07-13 18:43
1411 查看
一、简介
java提供了一个ServerSocket类表示服务器Socket。服务器Socket在服务器上运行,监听入站ftp连接。每个服务器Socket监听服务器上的一个特定端口。当远程注解上的一个客户端尝试这个端口时,服务器就会被唤醒,协商建立客户端与服务器端的连接,并返回一个常规的Socket对象,表示2台主机之间的Socket。也是就说服务器端Socket接受到客户端Socket发送过来的连接时,服务器端会生成一个常规的Socket对象,用于向客户端发送数据,数据总是通过常规socket进行传输。二、使用ServerSocket类
ServerSocket类包含了使用java编写服务器所需要的全部内容。其中包括创建新ServerSocket对象的构造函数,在指定端口监听客户端的连接的方法、配置各个服务器Socket选项的方法,以及一些其他常用的方法,如toString()。在java中,Server服务器的基本生命周期包含以下几个:
1.使用一个ServerSocket()构造函数在一个特定的端口创建一个新的ServerSocket对象。
2.ServerSocket使用他的accept()方法来监听这个端口的入站连接。accept会一直阻塞,直到一个客户端尝试与服务器建立连接,此时accept将返回一个连接客户端和服务器Socket对象。
3.根据服务器的类型,会调用Socket对象的getInputStream或getOutputStream方法,或者这两个方法都调用,以获得客户端通信的输入和输出流。
4.服务器和客户端根据已经协商的协议交互,直到要关闭连接。
5.服务器或客户端关闭连接。
5服务器返回到第2不,等待下一次连接。
2.1 一个完整的接收/响应客户端的例子
<span style="font-family:Microsoft YaHei;">import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.net.ServerSocket; import java.net.Socket; /** * Socket服务器端测试类 * @author zzj * @date Jul 14, 2016 11:35:32 AM */ public class ServerSocketTest { public static void main(String[] args) { testCommon(); } /** * 1.测试普通的server * @author zzj */ public static void testCommon(){ ServerSocket serverSocket=null; try { serverSocket = new ServerSocket(22); while(true){ System.out.println("wait receive message from client..."); //接收客户端连接的socket对象 Socket connection =null; try { //接收客户端传过来的数据,会阻塞 connection=serverSocket.accept(); System.out.println("****received message from client******"); //读取客户端传过来的数据 readMessageFromClient(connection.getInputStream()); System.out.println("****received message from client end******"); //向客户端写入数据 writeMsgToClient(connection.getOutputStream(),"I am server message!!!"); connection.close(); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection!=null) { connection .close(); } } } } catch (Exception e) { e.printStackTrace(); }finally{ if (serverSocket!=null) { try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 读取客户端信息 * @param inputStream */ private static void readMessageFromClient(InputStream inputStream) throws IOException { Reader reader = new InputStreamReader(inputStream); BufferedReader br=new BufferedReader(reader); String a = null; while((a=br.readLine())!=null){ System.out.println(a); } } /** * 响应客户端信息 * @param outputStream * @param string */ private static void writeMsgToClient(OutputStream outputStream, String string) throws IOException { Writer writer = new OutputStreamWriter(outputStream); writer.append("I am server message!!!"); writer.flush(); writer.close(); } }</span>
<span style="font-family:Microsoft YaHei;">import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; /** * Socket客户端 * @author zzj * @date Jul 13, 2016 2:47:13 PM */ public class SocketTest { public static void main(String[] args) { writeToServer("localhost",22); } /** * 向服务器写数据 * @param serverHost socket服务器地址 * @param port 端口 * @author zzj */ public static void writeToServer(String serverHost,int port){ Socket socket = null; try { //1.建立客户端socket连接,指定服务器位置及端口 socket =new Socket("localhost",22); //2.得到socket读写流 OutputStream os=socket.getOutputStream(); PrintWriter pw=new PrintWriter(os); //输入流 InputStream is=socket.getInputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(is)); //3.利用流按照一定的操作,对socket进行读写操作 String info="用户名:1,用户密码:1"; pw.write(info); pw.flush(); socket.shutdownOutput(); //接收服务器的相应 String reply=null; while(!((reply=br.readLine())==null)){ System.out.println("接收服务器的信息:"+reply); } //4.关闭资源 br.close(); is.close(); pw.close(); os.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); }finally{ if (socket!=null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } } </span>
2.2 多线程接收客户端信息
由于服务器再等待客户端连接并处理时,会处理完一个才会处理下一个,导致资源浪费或者客户端等待时间过长,这里做一次简单的优化,每次收到客户端的请求连接时,就开启一个线程来处理响应,只需要将上面的server代码简单的改下并封装即可:<span style="font-family:Microsoft YaHei;">** * Socket服务器端开启线程测试类 * @author zzj * @date Jul 14, 2016 11:35:32 AM */ public class ServerSocketThreadTest { public static void main(String[] args) { testCommon(); } /** * 1.测试普通的server * @author zzj */ public static void testCommon(){ ServerSocket serverSocket=null; try { serverSocket = new ServerSocket(22); while(true){ System.out.println("wait receive message from client..."); //接收客户端连接的socket对象 Socket connection =null; //接收客户端传过来的数据,会阻塞 connection=serverSocket.accept(); new SubThread(connection).start(); } } catch (Exception e) { e.printStackTrace(); }finally{ if (serverSocket!=null) { try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } } class SubThread extends Thread{ private Socket connection; public SubThread(Socket conSocket){ this.connection=conSocket; } public void run(){ try { System.out.println("****received message from client******"); //读取客户端传过来的数据 readMessageFromClient(connection.getInputStream()); System.out.println("****received message from client end******"); System.out.println(); //向客户端写入数据 writeMsgToClient(connection.getOutputStream(),"I am server message!!!"); connection.close(); } catch (Exception e) { e.printStackTrace(); }finally{ if (connection!=null) { try { connection .close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 读取客户端信息 * @param inputStream */ private static void readMessageFromClient(InputStream inputStream) throws IOException { Reader reader = new InputStreamReader(inputStream); BufferedReader br=new BufferedReader(reader); String a = null; while((a=br.readLine())!=null){ System.out.println(a); } } /** * 响应客户端信息 * @param outputStream * @param string */ private static void writeMsgToClient(OutputStream outputStream, String string) throws IOException { Writer writer = new OutputStreamWriter(outputStream); writer.append("I am server message!!!"); writer.flush(); writer.close(); } }</span>
2.3 线程池的方式改进多并发请求服务器问题
如果每次来一个请求,服务器端开启一个线程的话,有可能在同时来成千上万个请求时导致内存暴增而导致程序的崩溃,为了减轻开启线程导致的内存过高问题,这里采用线程池来缓解这个问题,下面为主要代码:package com.hq.socket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.itextpdf.text.pdf.PdfStructTreeController.returnType; /** * Socket服务器端开启线程测试类 * @author zzj * @date Jul 14, 2016 11:35:32 AM */ public class ServerSocketPoolTest { public static void main(String[] args) { testCommon(); } /** * 1.测试普通的server * @author zzj */ public static void testCommon(){ ServerSocket serverSocket=null; //定义一个容量为50的线程 ExecutorService service = Executors.newFixedThreadPool(50); try { serverSocket = new ServerSocket(220); while(true){ System.out.println("wait receive message from client..."); //接收客户端连接的socket对象 Socket connection =null; //接收客户端传过来的数据,会阻塞 connection=serverSocket.accept(); service.submit(new SubThread(connection)); } } catch (Exception e) { e.printStackTrace(); }finally{ if (serverSocket!=null) { try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } } class SubPolThread implements Callable<Boolean>{ private Socket connection; public SubPolThread(Socket conSocket){ this.connection=conSocket; } /** * 读取客户端信息 * @param inputStream */ private static void readMessageFromClient(InputStream inputStream) throws IOException { Reader reader = new InputStreamReader(inputStream); BufferedReader br=new BufferedReader(reader); String a = null; while((a=br.readLine())!=null){ System.out.println(a); } } /** * 响应客户端信息 * @param outputStream * @param string */ private static void writeMsgToClient(OutputStream outputStream, String string) throws IOException { Writer writer = new OutputStreamWriter(outputStream); writer.append("I am server message!!!"); writer.flush(); writer.close(); } /* (non-Javadoc) * @see java.util.concurrent.Callable#call() */ @Override public Boolean call() throws Exception { try { System.out.println("****received message from client******"); //读取客户端传过来的数据 readMessageFromClient(connection.getInputStream()); System.out.println("****received message from client end******"); System.out.println(); //向客户端写入数据 writeMsgToClient(connection.getOutputStream(),"I am server message!!!"); connection.close(); } catch (Exception e) { e.printStackTrace(); return false; }finally{ if (connection!=null) { try { connection .close(); } catch (IOException e) { e.printStackTrace(); } } } return true; } }
相关文章推荐
- 小心服务器内存居高不下的元凶--WebAPI服务
- 运维入门
- Seafile Server本地权限提升漏洞(CVE-2014-5443)
- 从USB安装Ubuntu Server 10.04.3 图文详解
- 肯特·贝克:改变人生的代码整理魔法
- 你应该学习哪种编程语言?
- 利用开源软件打造自己的全功能远程工具
- Linux5.9无人值守安装
- 数据中心和云未来的十二大趋势
- 使用zabbix监控Nginx活动状态--Part1
- 高效访问Internet-启用ISA Server的缓存
- 虚拟化基础架构Windows 2008篇之11-WSUS服务器的安装与配置
- 用vsftp快速搭建ftp服务器
- Linux快速构建apache web服务器
- 服务器监控策略浅谈
- [转]我们需要一种其他人能使用的编程语言
- windows server域用户提升到本地更高权限组中的方法
- DB2编程序技巧(1)
- DB2编程序技巧 (四)