基于BIO的实时Socket读写操作
文章目录
- 前言
- Socket类
2.1 Socket的通信过程
2.2 控制Socket连接
2.3 设置Socket的选项 - ServerSocket类
3.1 构造ServerSocket
3.2 ServerSocket的常用方法
3.3 设置ServerSocket选项 - 基于TCP的BIO通信
4.1 实现功能
4.2 程序源代码
4.3 程序效果截图
1. 前言
基于传输层协议TCP的网络通信是可靠的、有序的、差错控制的。TCP是面向连接的、可靠的流服务协议。TCP协议中,只有实现连接的双发才可以进行通信,因此广播和多播不是基于TCP的。下面首先介绍一些Socket和ServerSocket。
服务器、客户端建立通信的过程如下:
在这里插入图片描述
- 服务器网络接口的IP地址为10.1.1.1。服务器端应用程序在80端口运行服务,建立ServerSocket,并监听有无连接请求。
- 客户端必须知道服务器的IP地址或主机名、服务开放端口,客户端向服务器的服务Socket(10.1.1.1:80)发起请求。
- 服务器一旦接收该请求,就会在80端口上建立一个Socket,该Socket的本地地址为10.1.1.1:80,外部地址为客户端建立的Socket(client端IP地址,client端port)。客户端port通常由操作系统指定。
- 服务器每接收一个客户端的请求,就会在服务端口上建立一个Socket,这些Socket的本地地址相同,但外部地址各不相同。每个外部地址即各个客户端的本地Socket。这样服务器既可以监听服务请求,又可以和每个客户端进行独立的通信。
- 客户端通过本地Socket与服务器进行通信、读写信息。就像打电话一样,一个号码呼叫另一个号码,一旦被呼叫者接听,通信链路就建立起来了,双方就可以通话了。
2. Socket类
2.1 Socket的通信过程
在这里插入图片描述
2.2 控制Socket连接
获取Socket的输入流和输出流
服务端和客户端之间通信的Socket一旦连接,就会通过一对输入输出流进行通信。如同打电话时,一旦被叫放接听,双方通话的业务信道建立,就可以交流了。
Socket的getInputStream()方法和getOutputStream()方法分别实现获得输入流和输出流。
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));BufferedReader br = new BufferedReader(new IntputStreamReader(socket.getInputStream()));
获取Socket的地址端口信息
如果需要获得本地或者远程Socket的地址和端口信息,可以使用以下方法:
getInetAddress() //获得远程服务器的IP地址getPort() //获得远程服务器的端口getLocalAddress() //获得客户端本地的IP地址getLocalPort() //获得客户端本地的端口
关闭Socket
当客户端与服务器的通信结束时,应该关闭Socket,以释放Socket占用的包括
InputStream和OutputStream在内的各种资源。if(!s.isClosed()) s.close();//判断如果不是空的话则关闭
Socket的状态
Socket类提供了3中方法(isBound 、isClosed 和 isConnected)来判断Socket的状态。
isBound方法用来判断Socket的绑定状态,只要曾经绑定过,即使Socket已经关闭,仍然返回true。可以理解为本地是否曾经建立过到远程主机的Socket连接。
isClosed方法用来判断Socket是否已经关闭。
isConnected方法用来判断Socket的连接状态。和isBound方法一样,即使Socket已经关闭,仍然返回true,isConnected的状态不清楚。可以理解为到远程主机的Socket是否曾经连接过。
3. 基于TCP的BIO通信
3.1 实现功能
服务器创建服务并监听端口,与客户端建立连接,并向客户端转发消息,客户端输入quit命令即可退出。
3.2 程序源代码
Server类:
package com.company.bio;
import java.io.*;import java.net.ServerSocket;import java.net.Socket;
public class Server { public static void main(String[] args){ final String QUIT = "quit"; final int DEFAULT_PORT = 8888; ServerSocket serverSocket = null;
//绑定监听端口 try{ serverSocket = new ServerSocket(DEFAULT_PORT); System.out.println("启动服务器,监听端口"+DEFAULT_PORT);
while (true){ // 等待客户端连接 Socket socket = serverSocket.accept(); System.out.println("客户端[" + socket.getPort() + "]已连接"); //创建IO流 BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(socket.getInputStream()) ); BufferedWriter bufferedWriter = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream()) );
String msg = null; while ((msg = bufferedReader.readLine()) != null) { // 读取客户端发送的消息,当对方关闭时返回null
System.out.println("客户端["+socket.getPort()+"]:"+ msg); //回复客户发送的消息 bufferedWriter.write("服务器:" + msg + "\n"); bufferedWriter.flush(); //保证缓冲区的数据发送出去 //查看客户端是否退出 if(QUIT.equals(msg)){ System.out.println("客户端["+socket.getPort()+"]已退出"); break; } } } }catch (IOException e){ e.printStackTrace(); }finally { if (serverSocket != null){ try { serverSocket.close(); System.out.println("关闭ServerSocket"); } catch (IOException e) { e.printStackTrace(); } } } }}
Client类:
package com.company.bio;
import java.io.*;import java.net.Socket;
public class Client { public static void main(String[] args) { final String QUIT = "quit"; final String DEFAULT_SERVER_HOST = "127.0.0.1"; final int DEFAULT_SERVER_PORT = 8888; Socket socket = null; BufferedWriter bufferedWriter = null;
try{ // 创建socket socket = new Socket(DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT); //创建IO流 BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(socket.getInputStream()) ); bufferedWriter = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream()) ); //等待用户输入信息 BufferedReader consolReader = new BufferedReader( new InputStreamReader(System.in) ); while (true) { String input = consolReader.readLine(); //发送消息给服务器 bufferedWriter.write(input + "\n"); bufferedWriter.flush(); //读取服务器返回的消息 String msg = bufferedReader.readLine(); System.out.println(msg);
//查看用户是否退出 if(QUIT.equals(input))break; } }catch (IOException e){ e.printStackTrace(); }finally { if(bufferedWriter != null){ try { bufferedWriter.close(); System.out.println("关闭socket"); } catch (IOException e) { e.printStackTrace(); } } } }}
3.3 程序效果截图
Client:
在这里插入图片描述
Server:
在这里插入图片描述
更多资源和教程请关注公众号:非科班的科班。
如果觉得我写的还可以请给个赞,谢谢大家,你的鼓励是我创作的动力
基于BIO的实时Socket读写操作的更多相关文章
- 一个I/O线程可以并发处理N个客户端连接和读写操作 I/O复用模型 基于Buf操作NIO可以读取任意位置的数据 Channel中读取数据到Buffer中或将数据 Buffer 中写入到 Channel 事件驱动消息通知观察者模式
Tomcat那些事儿 https://mp.weixin.qq.com/s?__biz=MzI3MTEwODc5Ng==&mid=2650860016&idx=2&sn=549 ...
- NX二次开发-基于MFC界面的NX对Excel读写操作(OLE方式(COM组件))
NX二次开发API里没有对EXCAL读写操作的相关函数,市面上有很多种方法去实现,比如UFUN调KF,ODBC,OLE(COM组件)等等.这里我是用的OLE(COM组件)方式去做的,这种在VC上创建的 ...
- NX二次开发-基于NX开发向导模板的NX对Excel读写操作(OLE方式(COM组件))
在看这个博客前,请读者先去完整看完:NX二次开发-基于MFC界面的NX对Excel读写操作(OLE方式(COM组件))https://ufun-nxopen.blog.csdn.net/article ...
- linux下mysql基于mycat做主从复制和读写分离之基础篇
Linux下mysql基于mycat实现主从复制和读写分离1.基础设施 两台虚拟机:172.20.79.232(主) 172.20.79.233(从) 1.1软件设施 mysql5.6.39 , my ...
- 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程
Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...
- 基于AHB总线的master读写设计(Verilog)
一.AHB总线学习 1. AHB总线结构 如图所示,AHB总线系统利用中央多路选择机制实现主机与从机的互联问题.从图中可以看出,AHB总线结构主要可分为三部分:主机.从机.控制部分.控制部分由仲裁器. ...
- socket读写返回值的处理
在调用socket读写函数read(),write()时,都会有返回值.如果没有正确处理返回值,就可能引入一些问题 总结了以下几点 1当read()或者write()函数返回值大于0时,表示实际从缓冲 ...
- 基于Xenomai的实时Linux分析与研究
转自:http://blog.csdn.net/cyberlabs/article/details/6967192 引 言 随着嵌入式设备的快速发展,嵌入式设备的功能和灵活性要求越来越高,很多嵌入式设 ...
- berkerly db 中简单的读写操作(有一些C的 还有一些C++的)
最近在倒腾BDB,才发现自己确实在C++这一块能力很弱,看了一天的api文档,总算是把BDB的一些api之间的关系理清了,希望初学者要理清数据库基本知识中的环境,句柄,游标的基本概念,这样有助于你更好 ...
随机推荐
- Visioi形状相关应用
选择手柄为白点 按住shift的同时移动白点更为灵活 黄色的点就是控制手柄(只有一维图形有) 当调整形状出现绿色边的时候说明:这个时候这个形状的边等于了某个形状的长 铅笔工具可以移动控制点来更形状 ...
- JSR-133内存模型手册
1.介绍 JVM支持多种线程的执行,Threads代表的是线程类,位于java.lang.Thread包下,唯一的方式就是为用户在这个类下的对象创建线程,每一个线程关联着一个对象,一个线程将在star ...
- WPF继续响应被标记为已处理事件的方法
WPF继续响应被标记为已处理事件的方法 WPF中在冒泡事件或者隧道事件会随其层间关系在visual tree上层层传递,但是,某些事件传递到某些控件是即会”终止“(不再响应相应的注册事件),给人一种事 ...
- 【汇编】1.汇编环境的搭建:DOSBox的安装
前言 DOSBox是一款在windows系统运行DOS程序的环境模拟器.可以解决在64位机中汇编程序编译调试等问题. 本文以 DOSBox 0.74 为例,汇编编译程序采用MASM6. 第一步下载相关 ...
- Maven 生命周期的概念(指令默认顺序执行)
生命周期的概念 IDEA中使用maven构建项目都集中放到了窗口右侧"Maven Projects"中,点击该区域可以直观的看到,maven中几个常用指令都归类为LifeCycle ...
- 腾讯自研万亿级消息中间件TubeMQ为什么要捐赠给Apache?
导语 | 近日,云+社区技术沙龙“腾讯开源技术”圆满落幕.本次沙龙邀请了多位腾讯技术专家围绕腾讯开源与各位开发者进行探讨,深度揭秘了腾讯开源项目TencentOS tiny.TubeMQ.Kona J ...
- Mysql备份与恢复(1)---物理备份
数据库对企业来说最重要的莫过于其中的数据,所以做好数据库的备份是一个不可或缺的工作.数据库及时备份可以帮助我们在数据库出现异常宕机时及时的使用备份数据进行恢复工作,将因为数据库宕机产生的影响降低到最小 ...
- 【转】Java 面试题问与答:编译时与运行时
在开发和设计的时候,我们需要考虑编译时,运行时以及构建时这三个概念.理解这几个概念可以更好地帮助你去了解一些基本的原理.下面是初学者晋级中级水平需要知道的一些问题. Q.下面的代码片段中,行A和行B所 ...
- mongodb学习(一)——简介和基本操作
简介 MongoDB 是一个基于分布式文件存储的数据库 属于NoSQL数据库,是介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的 旨在为WEB应用提供可扩展的高性 ...
- docker制作cenos+php56+nginx镜像
首先你环境要安装好docker 1 获取centos镜像. docker search centos 选取第一个官方镜像. docker pull docker.io/centos 新建镜像挂载目录 ...
