c/s模型:tcp,udp构建客户端和服务器端(bio实现

hyhy904 hyhy904     2022-12-14     581

关键词:

Java中提供了socket编程来构建客户端和服务器端

TCP
构建服务器端的步骤:
(1)bind:绑定端口号
(2)listen:监听客户端的连接请求
(3)accept:返回和客户端连接的实例
(4)read/write:进行读写操作,也就是和客户端进行交互
(5)close:关闭资源
Java中提供了ServiceSocket关键字来构建服务器,在Java中listen和accept合并为一个accept操作,下面通过代码演示一下这5个步骤

public class Server
public static void main(String[] args) throws IOException
ServerSocket serverSocket = new ServerSocket();
//bind:绑定ip和端口
serverSocket.bind(new InetSocketAddress(6666));
//listen监听并且accpet返回socket实例
Socket accept = serverSocket.accept();
//通过socket拿到输入流和输出流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
PrintStream printStream = new PrintStream(accept.getOutputStream());
//读到客户端发来的数据并打印
String s = bufferedReader.readLine();
System.out.println("收到客户端的数据:"+s);
//向客户端输出数据
printStream.println("啦啦啦啦服务器回消息:"+s);
//关闭流和socket
printStream.close();
bufferedReader.close();
serverSocket.close();


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
构建客户端的步骤:
(1)connect:通过IP地址和端口号连接服务器端
(2)read/write:进行读写操作,也就是和服务器端进行信息交流
(3)close:关闭资源
可以看到相比于服务器端,客户端的操作要简单很多
由于我们写的是TCP协议下的,所以要先启动服务器端,服务器端启动后,在accept会等待客户端的连接,也就是说代码在这里会阻塞住,客户端在这个时候连接就可以了。
下面用代码演示一下这几个步骤:

public class Server
public static void main(String[] args) throws IOException
ServerSocket serverSocket = new ServerSocket();
//bind:绑定ip和端口
serverSocket.bind(new InetSocketAddress(6666));
//listen监听并且accpet返回socket实例
Socket accept = serverSocket.accept();
//通过socket拿到输入流和输出流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
PrintStream printStream = new PrintStream(accept.getOutputStream());
//读到客户端发来的数据并打印
String s = bufferedReader.readLine();
System.out.println("收到客户端的数据:"+s);
//向客户端输出数据
printStream.println("啦啦啦啦服务器回消息:"+s);
//关闭流和socket
printStream.close();
bufferedReader.close();
serverSocket.close();


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这两个demo都用到了缓冲流和打印流来进行读写操作,下面看一下运行的结果

 

下面通过画图来描述一下这个过程

通过这幅图也会很清楚的知道三次握手和四次挥手分别发生在什么时候

下面想一个需求,如果是多个客户端和服务器端进行信息的交流怎么办?

刚才已经提到了,服务器端accpet操作是等待客户端连接的操作,那么写一个循环,每一个循环体里面有一个accept不就可以解决多个客户端连接服务器端的问题了,但是要注意一点的是accpet是一个阻塞操作,所以需要多个线程才可以,下面解释一下为什么:
首先需要明白的是只需要对服务器端进行修改即可,所以这块都是针对服务器端说的
如果只有一个线程,那么通过accpet连接上,那么这个线程还要用啦进行读写,在读写的时候也会阻塞,如果读写的时候阻塞了,那么下一个accpet就是不能正常连接的,线程就一直停到第一个连接上了,直到该连接完毕结束后才可以下一个连接,很明显这个过程是一个串行的过程,达不到所要的效果,这就需要多线程,主线程只用来保持连接(accpet),然后子线程负责和客户端进行读写交互,这样的话子线程在读写阻塞的时候是不会影响到主线程的。

下面先来看看多个客户端一个服务器端的代码:
下面的代码只展示服务器端,客户端和上面保持不变

public class MutileServer
public static void main(String[] args)
//创建有3个固定数量线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
try
ServerSocket sockets = new ServerSocket(6666);
System.out.println("服务器已启动,正在等待连接");
while(true)
Socket accept = sockets.accept();
System.out.println("客户端:"+accept.getInetAddress().getHostAddress());
executorService.execute(new MyThread(accept));

catch (IOException e)
e.printStackTrace();



class MyThread implements Runnable
private Socket socket;
private BufferedReader bufferedReader;
private PrintStream printStream;
public MyThread(Socket socket)
this.socket = socket;
try
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
printStream = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
catch (IOException e)
e.printStackTrace();

@Override
public void run()
try
String s = bufferedReader.readLine();
System.out.println("客户端发来消息 "+s);
printStream.println("echo"+s);
printStream.flush();
bufferedReader.close();
printStream.close();
catch (IOException e)
e.printStackTrace();



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
需要说明的几点:
(1)这块我用到了线程池,不用多次创建线程,方便统一管理并且高效。也可以单独创建多个线程,通过循环也是可以的。
(2)我写了一个MyThread类专门用来处理读写和客户端的信息交流,也就是子线程完成读写操作,主线程只用关心和服务器端的连接即可。
(3)用完资源后必须关闭,并且尽量不要抛异常,在当前方法中处理一下。

缺点
用BIO实现TCP客户端和服务器端是有缺点的,BIO是同步阻塞模型,在JDK1.4之前一直使用这种模型,但是想这样一个问题,客户端每过来一个连接服务器端就要有一个线程与之对应,那么客户端非常多的情况下,服务器端线程就会非常多,而且线程上下文切换也会成为一笔非常大的消耗,这就是BIO的缺点,如果要改善这种缺点,就需要引入NIO。

UDP
UDP不像TCP是可靠的连接,也就是会保证数据的正确送达,而UDP会以数据报的形式扩散数据,举一个很简单的例子:听广播,当节目到达时必须提前打开收音机,这样才会保证不会错过。UDP也是一样,服务器端发送数据时,客户端需要提前等着,以免错过数据。
UDP完成客户端和服务器端需要两个类:DatagramPacket和DatagramSocket
DatagramSocket是建立连接的套接字,可以理解为运送货物的码头
DatagramPacket是数据包,也就是说数据在传送过程中是被打包成了数据包,如果DatagramSocket是码头,那么DatagramPacket就是装载货物的箱子。

看一下代码:
Server:

public class Server
public static void main(String[] args)
//要发送的数据
String data = "数据发送了。。。";
byte[] bytes = data.getBytes();

try
//包装成数据包的形式
DatagramPacket packet = new DatagramPacket(bytes, bytes.length,InetAddress.getByName("127.0.0.1"), 8888);
//初始化DatagramSocket
DatagramSocket socket = new DatagramSocket();
//发送数据
socket.send(packet);
catch (IOException e)
e.printStackTrace();



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Client:

public class Client
public static void main(String[] args)
try
//选择监听的端口号
DatagramSocket socket = new DatagramSocket(8888);
//初始化接收数据包
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
//接收数据
socket.receive(packet);
//解析数据包
String s = new String(packet.getData(), 0,packet.getLength());
//打印接收到的数据
System.out.println(s);
catch (IOException e)
e.printStackTrace();



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
先启动客户端,然后再启动服务器
---------------------

网络编程socket模块tcp协议udp协议

...块,tcp协议通信代码网络基础相关知识(1)架构C/S架构:client客户端和server服务器端优势:能充分发挥pc机的性能B/S架构:browser浏览器和server服务器隶属于C/S架构B/S架构同意了应用的接口(2)通信同意台电脑上两个py程序通信:打开一个文... 查看详情

golang学习十:网络编程(代码片段)

...lient3.TCP通信3.1三次握手:3.2四次挥手:4.UDP:4.1UDP服务器4.2UDP客户端:4.3UDP并发:5.UDP与TCP的差异三、实例--文件传输:1.流程简析2.获取文件属性:3.客户端实现4.服务端实现:四、示例-并发聊天室:1模块简述2.广播用户上线3.广播用户消息4.... 查看详情

udp、tcp协议区别?

...正常通信了。注意:HTTP是基于TCP协议的,所以每次都是客户端发送请求,服务器应答,但是TCP还可以给其他应用层提供服务,即可能A、B在建立链接之后,谁都可能先开始通信。如果采用两次握手,那么只要服务器发出确认数据... 查看详情

c/s模型之udp协议

 说明:利用UDP协议,创建一个服务器和一个客户端。两者间进行通信。由客户端进行输入内容,而服务器将接受的内容进行再一次返回,并显示在服务端。//UDP_Seversock.cpp:定义控制台应用程序的入口点。#include"stdafx.h"#include&l... 查看详情

网络编程(代码片段)

...案一5.3.2解决方案进阶6socket的更多方法介绍7扩展:验证客户端链接的合法性8socketserverViewCode1一.楔子2二.软件开发的架构2.11.C/S架构2.22.B/S架构 3三.网络基础3.1ip和端口3.2osi七层模型  3.2.1引子  3.2.2osi七层模型3.3socket概念... 查看详情

http协议

1、数据库、tomcat?2、c/s:client---service客户端、APP、服务器,整个叫c/s架构,客户端一般是安装包3、b/s:browse---service需要浏览器,客户端需要页面4、ajax基于tcp协议,tcp协议安全,耗性能;网络电话:UDP协议5、通信协议三要素:... 查看详情

java编程基础之网络编程(代码片段)

...议数据传输发送端接收端udp数据传输丢失问题TCP概述Socket客户端ServerSocket服务端Socket**服务器代码**客户端代码文件上传实现客户端服务端多线程版概述C/S和B/S网络通信协议协议:protocol网络通信协议市要求双方传递数据的计算机... 查看详情

python面试题网络编程和数据库(代码片段)

...流程。(3分)#1.三次握手是tcp协议建立连接的过程#2.由客户端发起一个syn请求,服务端接收并回复(synack)#客户端收到ack和syn之后再回复一个ack#3.在原生的socket代码中三次握手是由acceptconnect2.四次挥手是tcp协议断开连接的过程由客... 查看详情

c/s模型之tcp群聊

...:利用TCP协议和多线程实现群聊功能。一个服务器,多个客户端(同一个程序多次启动)。客户端向服务端发送数据,由服务端进行转发到其他客户端。/服务端//WSASever.cpp:定义控制台应用程序的入口点。//#include"stdafx.h"#include<... 查看详情

c/s模式b/s模式

C/S模式(Client/Server)客户端和服务端C/S模式中服务端中主要进行业务交互,数据存储,考虑并发,高可用等,客户端主要是页面展示,将服务端返回去的内容展示在客户端,将客户端提交的信息做一处理 。B/S(Browser/Server)... 查看详情

并发和数据库

...简述TCP三次握手、四次回收的流程。(3分)建立连接由客户端发起一个syn请求,服务端接收并回复(acksyn)客户端收到ack和syn之后再回复一个ack确认在原生的socket代码中三次握手是由acceptconnect断开连接 客户端向服务端发起请... 查看详情

udp与tcp

...t封装,构造方法如下数据报对象用DatagramPacket封装TCP 客户端用Sokect类进行封装。  服务器端用Sever 查看详情

c/s通信模型与b/s通信模型介绍

1、客户端与服务器之间的通信模型基于Socket连接的客户端与服务器之间的通信模型图如上图所示,整个通信过程如下所示:(1)服务器端首先启动监听程序,对指定的端口进行监听,等待接收客户端的连接请求;(2)客户端程... 查看详情

探索udp套接字编程

...者的适用场景不同罢了。  典型的UDP套接字编程模型是客户端不予服务端建立连接,而只是调用sendto函数来向服务端发 查看详情

探索udp套接字编程

...者的适用场景不同罢了。  典型的UDP套接字编程模型是客户端不予服务端建立连接,而只是调用sendto函数来向服务端发送数 查看详情

udp打洞原理和源代码。

所谓udp打洞就是指客户端A通过udp协议向服务器发送数据包,服务器收到后,获取数据包,并且可获取客户端A地址和端口号。同样在客户端B发送给服务器udp数据包后,服务器同样在收到B发送过来的数据包后获取B的地址和端口号... 查看详情

十网络编程

...目标编写一个C/S或B/S架构的基于网络通信的软件C/S架构:客户端---服务端B/S架构:浏览器----服务端学习socket编程就是要编写客户端软件和服务端软件,然后实现服务端和客户端基于网络通信服务端特点:1、不间断地提供服务;2... 查看详情

网络编程

网络编程1.网络编程概述(1).C/S结构:指客户端与服务端结构,常见程序QQ;(2).B/S结构:指浏览器和服务器的结构;2.网络编程的三要素:*IP地址*端口号*通信协议(UDP/TCP)*IP地址类(InetAddress类)一个IP地址就对应一个InetAddress类的对象。InetAddre... 查看详情