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 ...
随机推荐
- 【答疑解惑】为什么你的 Charles 会抓包失败?
作为一名 Web 开发工程师,天天都会和网络打交道.Charles 作为一款网络抓包工具,几乎成了 Web 开发的标配. 本文是我深度使用 Charles 后总结而成,不同于其它介绍 Charles ...
- 轻轻松松学CSS:overflow
一.overflow的定义 overflow,音[əʊvəˈfləʊ],义[溢出],就像2.2米的人躺在1.8米的床上,腿得耷拉到床外一样.overflow 属性用于控制内容溢出容器时显示的方式 二. ...
- C面向对象: 升级版本实现:同步逻辑、少量连续失败则增补、多次连续失败则拉长同步周期
// C语言之 面向对象+虚事务的抽象 /*********** 进阶练习: (对虚的事物的抽象) 完善部门职责 ***********************/ #include <stdio ...
- 【音乐爬虫】Python爬虫-selenium+browsermob-proxy 解决动态网页 js渲染问题
1.一般的python爬虫很简单,直接请求对应网址,解析返回的数据即可,但是有很多网站的数据的js动态渲染的,你直接请求是得不到对应的数据的 这时就需要其它手段来处理了. 2.以一个例子来说明,整个过 ...
- SetDlgItemText()与UpdateData()的区别
转载:https://blog.csdn.net/qq_20161893/article/details/72818874 SetDlgItemText(IDC_EDIT_RXDATA,m_strRE ...
- Matlab中fspecial的用法
来源:https://blog.csdn.net/hustrains/article/details/9153553 Fspecial函数用于创建预定义的滤波算子,会与imfilter搭配使用,其语法 ...
- MATLAB textread函数
实际应用中经常要读取txt文件,这个时候就需要用到强大的textread函数.它的基本语法是:[A,B,C,...] = textread(filename,format)[A,B,C,...] = ...
- linux centos 04
1.python的虚拟环境 1.将当前机器上的解释器作为一个 本地,复制出的很多歌 虚拟解释器 物理机上的 本体解释器 ,什么事也不做 分身1: 解释器1:虚拟环境1 运行django 1 ...
- windows.h头文件中改变光标位置的函数——SetConsoleCursorPosition
COORD 具体为 typedef struct COORD{ short X; short Y; } COORD,*PCOORD; 可以用来记录坐标. #include <iostre ...
- 【UR #9】App 管理器
UOJ小清新题表 题目内容 UOJ链接 一句话题意:给出一个强联通的混合图,有一些有向边和无向边.删除一些边使其维持强联通的状态,求删边方案. 数据范围 \(1\leq n\leq 5000,0\le ...