java网络编程(二)复用Socket连接以及使用多线程完成多个客户端的连接
2016-01-26 16:20
507 查看
在前面的示例中,客户端中建立了一次连接,只发送一次数据就关闭了,这就相当于拨打电话时,电话打通了只对话一次就关闭了,其实更加常用的应该是拨通一次电话以后多次对话,这就是复用客户端连接。
那 么如何实现建立一次连接,进行多次数据交换呢?其实很简单,建立连接以后,将数据交换的逻辑写到一个循环中就可以了。这样只要循环不结束则连接就不会被关 闭。按照这种思路,可以改造一下上面的代码,让该程序可以在建立连接一次以后,发送三次数据,当然这里的次数也可以是多次,示例代码如下:
现在客户端可以向服务器发生三次请求且获取三次相应,而我们服务器端是对话一次数据以后就关闭了连接,如果服务器端程序关闭了,客户端继续发送数据肯定会出现异常
按照客户端实现的逻辑,也可以复用服务器端的连接,实现的原理也是将服务器端的数据交换逻辑写在循环中即可,按照该种思路改造以后的服务器端代码为:
在该示例代码中,也将数据发送和接收的逻辑写在了一个for循环内部,只是在实现时硬性的将循环次数规定成了3次,这样代码虽然比较简单,但是通用性比较差,客户端和服务器端的次数控制还不够灵活,如果客户端的次数不固定怎么办呢?不着急,这个问题会一一进行解答。
现在我们学习另外一个网络编程的突出问题。
如何使服务器端支持多个客户端同时工作?
前面介绍的服务器端程序,只是实现了概念上的服务器端,离实际的服务器端程序结构距离还很遥远,如果需要让服务器端能够实际使用,那么最需要解决的问题就是——如何支持多个客户端同时工作。
一个服务器端一般都需要同时为多个客户端提供通讯,如果需要同时支持多个客户端,则必须使用线程的来解决。简单来说,也就是当服务器端接收到一个连接时,启动一个专门的线程处理和该客户端的通讯。
按照这个思路改写的服务端示例程序将由两个部分组成,SocketService类实现服务器端控制,实现接收客户端连接,然后开启专门的逻辑线程处理该连接,LogicThread类实现对于一个客户端连接的逻辑处理,将处理的逻辑放置在该类的run方法中。该服务端示例的代码实现为:
每次使用一个连接对象构造该线程,该连接对象就是该线程需要处理的连接,在线程构造完成以后,该线程就被启动起来了,然后在run方法内部对客户端连接进行处理,数据交换的逻辑和前面的示例代码一致,都是IO流处理。
这里的示例还只是基础的服务器端实现,在实际的服务器端实现中,由于硬件和端口数的限制,所以不能无限制的创建线程对象,而且频繁的创建线程对象效率也比较低,所以程序中都实现了线程池来提高程序的执行效率。
那 么如何实现建立一次连接,进行多次数据交换呢?其实很简单,建立连接以后,将数据交换的逻辑写到一个循环中就可以了。这样只要循环不结束则连接就不会被关 闭。按照这种思路,可以改造一下上面的代码,让该程序可以在建立连接一次以后,发送三次数据,当然这里的次数也可以是多次,示例代码如下:
[code]public class SocketClient { public static void main(String[] args) { Socket socket = null; InputStream inputStream = null; OutputStream outputStream = null; String data[] = { "hello world1", "hello world2", "hello world3" }; try { // 创建Socket实例 socket = new Socket("hadoop", 10000); // 获取输出流,向服务器发生数据 outputStream = socket.getOutputStream(); /// 获取输入流,获取服务器的响应 inputStream = socket.getInputStream(); byte[] buff = new byte[1024]; // 循环发送 for (int i = 0; i < data.length; i++) { // 发送数据 outputStream.write(data[i].getBytes()); int len = inputStream.read(buff); // 打印服务端的相应 System.out.println(new String(buff, 0, len)); } } catch (Exception e) { e.printStackTrace(); } finally { // 释放资源 try { inputStream.close(); outputStream.close(); socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
现在客户端可以向服务器发生三次请求且获取三次相应,而我们服务器端是对话一次数据以后就关闭了连接,如果服务器端程序关闭了,客户端继续发送数据肯定会出现异常
按照客户端实现的逻辑,也可以复用服务器端的连接,实现的原理也是将服务器端的数据交换逻辑写在循环中即可,按照该种思路改造以后的服务器端代码为:
[code]public class SocketService { public static void main(String[] args) { InputStream inputStream =null; OutputStream outputStream =null; Socket socket = null; ServerSocket serviceSocket =null; try { //服务器端接收消息的类。定制端口号为8888 serviceSocket = new ServerSocket(10000); //获取socket。这个方法是阻塞式的 socket = serviceSocket.accept(); inputStream = socket.getInputStream(); byte buf[] = new byte[1024]; //向客户端生成响应 outputStream = socket.getOutputStream(); for(int i=0;i<3;i++){ int len =inputStream.read(buf); //打印客户端的消息 System.out.println(new String(buf,0,len)); outputStream.write("收到".getBytes()); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { //释放资源 try { outputStream.close(); inputStream.close(); socket.close(); serviceSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
在该示例代码中,也将数据发送和接收的逻辑写在了一个for循环内部,只是在实现时硬性的将循环次数规定成了3次,这样代码虽然比较简单,但是通用性比较差,客户端和服务器端的次数控制还不够灵活,如果客户端的次数不固定怎么办呢?不着急,这个问题会一一进行解答。
现在我们学习另外一个网络编程的突出问题。
如何使服务器端支持多个客户端同时工作?
前面介绍的服务器端程序,只是实现了概念上的服务器端,离实际的服务器端程序结构距离还很遥远,如果需要让服务器端能够实际使用,那么最需要解决的问题就是——如何支持多个客户端同时工作。
一个服务器端一般都需要同时为多个客户端提供通讯,如果需要同时支持多个客户端,则必须使用线程的来解决。简单来说,也就是当服务器端接收到一个连接时,启动一个专门的线程处理和该客户端的通讯。
按照这个思路改写的服务端示例程序将由两个部分组成,SocketService类实现服务器端控制,实现接收客户端连接,然后开启专门的逻辑线程处理该连接,LogicThread类实现对于一个客户端连接的逻辑处理,将处理的逻辑放置在该类的run方法中。该服务端示例的代码实现为:
[code]public class SocketService { public static void main(String[] args) { Socket socket = null; ServerSocket serviceSocket =null; try { //服务器端接收消息的类。定制端口号为8888 serviceSocket = new ServerSocket(10000); System.out.println("服务器已经启动"); while(true){ //获取socket。这个方法是阻塞式的 socket = serviceSocket.accept(); //一但获取连接后就开子线程来处理 new LogicThread(socket); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { //释放资源 try { serviceSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
[code]public class LogicThread extends Thread { Socket socket; InputStream inputStream; OutputStream outputStream; public LogicThread(Socket socket) { this.socket = socket; start(); // 启动线程 } public void run() { byte[] buf = new byte[1024]; try { // 初始化流 outputStream = socket.getOutputStream(); inputStream = socket.getInputStream(); for (int i = 0; i < 3; i++) { // 读取数据 int len = inputStream.read(buf); System.out.println(new String(buf,0,len)); // 反馈数据 outputStream.write("收到".getBytes()); } } catch (Exception e) { e.printStackTrace(); } finally { close(); } } /** * * 关闭流和连接 * */ private void close() { try { // 关闭流和连接 outputStream.close(); inputStream.close(); socket.close(); } catch (Exception e) { } } }
每次使用一个连接对象构造该线程,该连接对象就是该线程需要处理的连接,在线程构造完成以后,该线程就被启动起来了,然后在run方法内部对客户端连接进行处理,数据交换的逻辑和前面的示例代码一致,都是IO流处理。
这里的示例还只是基础的服务器端实现,在实际的服务器端实现中,由于硬件和端口数的限制,所以不能无限制的创建线程对象,而且频繁的创建线程对象效率也比较低,所以程序中都实现了线程池来提高程序的执行效率。
相关文章推荐
- Nginx HTTP返回状态码修改
- Android利用Get、Post 获取网络数据
- HttpWebRequest请求返回非200的时候 HttpWebResponse怎么接受返回错误提示
- AngualrJS中每次$http请求时的一个遮罩层Directive
- 深入Android通过Apache HTTP访问HTTP资源
- Exception in thread "http-bio-8081-exec-3" java.lang.OutOfMemoryError: PermGen space
- HAProxy一箭双雕——让一个端口完成两件事
- Android网络请求的第三库AsyncHttpclient
- 理解HTTP幂等性
- AngualrJS中每次$http请求时的一个遮罩层Directive
- linux网络子系统内核分析
- android Xutils Http模块分析
- JAVA利用HttpClient进行POST请求(HTTPS)
- DHT网络存储设计
- 项目修炼之路(2)测试-TCPCopy
- java网络编程(一)使用TCP协议完成客户端与服务端的数据传递
- http头文件User-Agent详解
- http header详解
- SGU 176 Flow construction-上下界网络流
- VirtualBox配置网络以及SSH登陆配置