Java:基于TCP协议网络socket编程(实现C/S通信)
目录
一、前言:TCP原理简介
首先,保证文章完整性,TCP的理论原理还是需要简介一下,略显枯燥๑乛◡乛๑。
TCP(传输控制协议,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP旨在适应支持多网络应用的分层协议层次结构。也就是说,TCP是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议。 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务。
以上TCP的特点,也正是与UDP的明显不同之处。UDP(用户数据报协议)是一种无连接的、不可靠的、不以字节流传输通信协议。具体区别可对比之前这篇文章:
【基于UDP协议网络Socket编程(java实现C/S通信案例) 】 [https://www.cnblogs.com/chenzhenhong/p/13825286.html]
接着,“三次握手”则是众所周知的一个词,是建立TCP连接的重要过程。许多文章有详细解读,本篇则是详细记录在此原理之上,使用Java实现TCP的Socket网络通信,包含C/S软件架构的程序设计,偏向实践,更加有趣!
二、Socket编程通信
本篇使用Java进行Socket编程,Java的TCP/IP套接字编程将底层的细节进行了封装,其编程模型如图:
我们自顶向下观察,基于TCP的通信,必然有服务端Server和客户端Client。
首先,建立连接。两端分别有一个套接字Socket,用于两者之间的通信。客户端向服务器发送请求,创建socket进行连接。服务端则随时监听客户端发起的请求,接收并创建裂解Socket。
其次,开始通信。服务和客户两端的输入输出流互相通信。逻辑上可理解为通信进程的双方具有两个流(输出流和输入流)。逻辑上可将两个流理解为两个通信管道的全双工通信模式,一个用于向对方发送数据,另一个用于接收对方的数据。
最后,结束通信。客户端访问服务器结束,断开连接,关闭Socket和相关资源(输入输出流等)。服务端监听客户端状态,同时关闭Socket等连接。
建立通信规则:
Server和Client之间需要约定相同的规则,保证正常通信。之后的程序设计,我们约定:
客户端连接服务器,连接成功后,服务器首先给客户端发送一条欢迎信息;
客户端程序每发送一条信息给服务器,服务器接收并回送该信息到客户端,客户端接收并显示该信息;
当客户端发送"bye",则结束对话。
三、TCP服务器端(具体代码)
第一步,创建服务端套接字。
类成员变量:ServerSocket serverSocket,监听端口号port;
private int port =8008;//服务器监听窗口
private ServerSocket serverSocket;//定义服务器套接字 public TCPServer() throws IOException{
serverSocket =new ServerSocket(port);
System.out.println("服务器启动监听在"+port+"端口..."); }
第二步,定义输入输出流方法:
private PrintWriter getWriter(Socket socket) throws IOException{
//获得输出流缓冲区的地址
OutputStream socketOut=socket.getOutputStream();
//网络流写出需要使用flush,这里在printWriter构造方法直接设置为自动flush
return new PrintWriter(new OutputStreamWriter(socketOut,"utf-8"),true);
} private BufferedReader getReader(Socket socket) throws IOException{
//获得输入流缓冲区的地址
InputStream socketIn=socket.getInputStream();
return new BufferedReader(new InputStreamReader(socketIn,"utf-8"));
}
第三步,服务端核心:
//单客户版本,每次只能与一个用户建立通信连接
public void Service(){
while (true){
Socket socket=null;
try {
//此处程序阻塞,监听并等待用户发起连接,有连接请求就生成一个套接字
socket=serverSocket.accept(); //本地服务器控制台显示客户连接的用户信息
System.out.println("New connection accepted:"+socket.getInetAddress());
BufferedReader br=getReader(socket);//字符串输入流
PrintWriter pw=getWriter(socket);//字符串输出流
pw.println("来自服务器消息:欢迎使用本服务!"); String msg=null;
//此处程序阻塞,每次从输入流中读入一行字符串
while ((msg=br.readLine())!=null){
//如果用户发送信息为”bye“,就结束通信
if(msg.equals("bye")){
pw.println("来自服务器消息:服务器断开连接,结束服务!");
System.out.println("客户端离开。");
break;
}
pw.println("来自服务器消息:"+msg);
}
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if (socket!=null)
socket.close();//关闭socket连接以及相关的输入输出流
}catch (IOException e){
e.printStackTrace();
}
}
}
}
代码关键解析很清楚易懂。可以看到,服务端提供服务放到了一个While(true)里面,这是因为服务器程序需要一直运行,所以处理代码一般放在while(true)这种无限循环中,TCPServer运行一次,且自身不能终止运行,要终止它运行,只能通过强制方式(如在IDE环境强制关闭)。
四、TCP客户端(具体代码)
第一步,创建客户端套接字,定义类构造方法,实现输入输出流。
private Socket socket; private PrintWriter pw;
private BufferedReader br; public TCPClient(String ip, String port) throws IOException{
//主动向服务器发起连接,实现TCP三次握手
//不成功则抛出错误,由调用者处理错误
socket =new Socket(ip,Integer.parseInt(port)); //得到网络流输出字节流地址,并封装成网络输出字符流
OutputStream socketOut=socket.getOutputStream();
//参数true表示自动flush数据
pw=new PrintWriter(new OutputStreamWriter(socketOut,"utf-8"),true); //得到网络输入字节流地址,并封装成网络输入字符流
InputStream socketIn=socket.getInputStream();
br=new BufferedReader(new InputStreamReader(socketIn,"utf-8")); }
第二步,实现网络通信发送和接收方法。
public void send(String msg){
//输出字符流,由socket调用系统底层函数,经网卡发送字节流
pw.println(msg);
} public String receive(){
String msg=null;
try {
//从网络输入字符流中读取信息,每次只能接受一行信息
//不够一行时(无行结束符),该语句阻塞
//直到条件满足,程序往下运行
msg=br.readLine();
}catch (IOException e){
e.printStackTrace();
}
return msg;
}
第三步,定义网络连接关闭方法供外部调用。
public void close(){
try {
if (socket!=null)
socket.close();
}catch (IOException e){
e.printStackTrace();
}
}
TCP连接的释放也有“四次握手”一说,必须经过2MSL后才真正释放。具体过程如下图:
五、通信效果演示
GIF动图演示:
六、“创意”机器人:价值一个亿的AI核心代码(具体代码)
这部分我们要实现“聊天机器人”,效果这样:
是不是迫不及待想知道如何实现呢!堪称“价值一个亿的AI核心代码”!!??
就这样实现了!
不卖关子了,就一行代码!
msg=msg.replace("?","!").replace("?","!").replace("吗","").replace("吗?","");
具体想实现机器人如何回复可以自行调整代码。
七、最后
本篇则是详细记录在此原理之上,使用Java实现TCP的Socket网络通信,包含C/S软件架构的程序设计,偏向实践,更加有趣!仔细阅读的朋友可以发现,在服务器端核心部分,有一行注释说明了该程序只支持单用户,也就是单线程通信,可以尝试一下,如果再开一个客户端连接该服务,是否因为单线程阻塞程序卡住了。
这个问题关键就在于:服务器和客户端互相约定通信规则,否则就可能有问题,例如,如果服务器在一个客户端连接成功后,并没有一条信息发送给客户端,客户端的读取欢迎信息的语句无法读取到内容,就被阻塞住,由于是单线程,甚至整个程序都会被卡住。要解决这个问题,等待更新下一篇!
另外,UI界面的设计可参考上一篇博客:【基于UDP协议网络Socket编程(java实现C/S通信案例) 】 [https://www.cnblogs.com/chenzhenhong/p/13825286.html]
我的博客园:https://www.cnblogs.com/chenzhenhong/p/13885290.html
我的CSDN博客:https://blog.csdn.net/Charzous/article/details/109260488
Java:基于TCP协议网络socket编程(实现C/S通信)的更多相关文章
- 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程
Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...
- 网络编程: 基于TCP协议的socket, 实现一对一, 一对多通信
TCP协议 面向连接 可靠的 面向字节流形式的 tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端 TCP协议编码流程: 服务器端: 客户端 实例化对 ...
- 基于TCP协议的socket编程
什么是socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面, ...
- Java修炼——基于TCP协议的Socket编程_双向通信_实现模拟用户登录
首先我们需要客户端和服务器端. 服务器端需要:1.创建ServerSocket对象.2.监听客户端的请求数据.3.获取输入流(对象流)即用户在客户端所发过来的信息. ...
- 基于TCP协议之socket编程
#服务端 #导入一个socket模块 import socket #想象成买手机打电话:socket.SOCK_STREAM 表示建立tcp连接 ,udp连接socket.SOCK_DGRAM #买了 ...
- 基于TCP(面向连接)的Socket编程
基于TCP(面向连接)的Socket编程 一.客户端: 1.打开一个套接字(Socket); 2.发起连接请求(connect); 3.如果连接成功,则进行数据交换(read.write.send.r ...
- 基于TCP/UDP的socket编程
基于TCP(面向连接)的socket编程服务器端顺序: 1. 创建套接字(socket) 2. 将套接字绑定到一个本地地址和端口上(bind) 3. 将套接字设为监听模式,准备接收客户请求(liste ...
- 基于TCP 协议的socket 简单通信
DNS 服务器:域名解析 socket 套接字 : socket 是处于应用层与传输层之间的抽象层,也是一组操作起来非常简单的接口(接受数据),此接口接受数据之后,交由操作系统 为什么存在 soc ...
- UDP协议网络Socket编程(java实现C/S通信案例)
我的博客园:https://www.cnblogs.com/chenzhenhong/p/13825286.html 我的CSDN博客:https://blog.csdn.net/Charzous/a ...
随机推荐
- 并发编程(六)Object类中线程相关的方法详解
一.notify() 作用:唤醒一个正在等待该线程的锁的线程 PS : 唤醒的线程不会立即执行,它会与其他线程一起,争夺资源 /** * Object类的notify()和notifyAll()方法详 ...
- kafka学习(四)kafka安装与命令行调用
文章更新时间:2020/06/07 一.安装JDK 过程就不过多介绍了... 二.安装Zookeeper 安装过程可以参考此处~ 三.安装并配置kafka Kafka下载地址 http://kafk ...
- spring aop 源码分析(三) @Scope注解创建代理对象
一.源码环境的搭建: @Component @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON,proxyMode = ScopedP ...
- Python-属性描叙符协议ORM实现原理依据- __set__ __get__ __delete__
class CheckString: def __init__(self, variable_type): self.variable_type = variable_type def __set__ ...
- mysql-9-limit
#进阶9:分页查询 /* 当要显示的数据,一页显示不全,需要分页提交sql请求 SELECT FROM JOIN ON WHERE GROUP BY HAVING ORDER BY LIMIT off ...
- 提升GAN的技术 Tips for Improving GAN
Wasserstein GAN (WGAN) 在一些情况下,用 JS散度来衡量两个分布的远近并不适合: 1. 数据是高维空间中的低维流形(manifold),两个分布在高维空间中的 overlap 少 ...
- 实验 2:Mininet 实验——拓扑的命令脚本生成
一.实验目的 掌握 Mininet 的自定义拓扑生成方法:命令行创建.Python 脚本编写 二.实验任务 通过使用命令行创建.Python 脚本编写生成拓扑,熟悉 Mininet 的基本功能. 三. ...
- Linux中的硬链接和软连接
1.Linux链接概念Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link).默认情况下,ln命令产生硬链接. [硬连接]硬连接指通过索引节点 ...
- 6-kubernetes网络
1.service存在的意义 防止破的失联(服务发现) 定义一组pod的访问策略(提供负载均衡) 2.pod与service的关系 通过label-selector相关联 通过service实现pod ...
- Linux 下 svn 场景实例及常用命令详解
一.SVN使用场景实例 问题: 在使用svn做为版本控制系统的软件开发中,经常会有这样的需求:在工作复本目录树的不同目录中增加了很多文件,但未纳入版本控制系统,这时如果使用svn add命令一个一个的 ...