C/S模型:TCP,UDP构建客户端和服务器端(BIO实现

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
先启动客户端,然后再启动服务器
---------------------

原文地址:https://www.cnblogs.com/hyhy904/p/10942149.html

时间: 2024-07-30 10:16:38

C/S模型:TCP,UDP构建客户端和服务器端(BIO实现的相关文章

OSI七层模型与 TCP/IP五层模型 TCP/UDP的区别

转自:http://blog.chinaunix.net/uid-22166872-id-3716751.html OSI七层模型OSI 中的层            功能                                                        TCP/IP协议族 应 用层                 文件传输,电子邮件,文件服务,虚拟终 端         TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 表示层          

基于UDP的客户端和服务器端的代码设计

实验平台 linux 实验内容 编写UDP服务器和客户端程序,客户端发送消息,服务器接收消息,并打印客户端的IP地址和端口号. 实验原理 UDP是无需连接的通信,其主要实现过程如下: 同样,我们可以按照上一篇博客:基于TCP的客户端和服务器端的代码设计 的办法,将服务器代码分成两部分,一个是初始化,一个是收发数据.但是UDP服务器初始化较为简单,也可以直接写在main函数里. UDP和TCP在读写数据上较为不同的是,sendto()和recvfrom(),这两个函数较为复杂.通过man手册查询得

Windows socket c++ TCP UDP 简单客户端 vs2013

socket 主要是网络中进程之间的通信,起源于Unix,而"一切皆可文件"的思想一样可以用在socket上,即 打开 -> 读写 -> 关闭. int socket(int domain, int type, int protocol):(服务端 & 客户端) socket函数对应于普通文件的打开操作.普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket. 这个so

TCP协议的客户端与服务器的通信过程

使用TCP时,客户端与服务器端的通信流程 服务器初始化1)调用socket,创建文件描述符fd2) 调用bind将fd与服务器的IP与PORT绑定3)调用listen将套接字设为监听模式,准备接收客户端连接请求4)调用accept等待并接收客户端的连接请求,建立好TCP连接后,该函数会返回一个新的已连接套接字newfd 建立连接1)客户端调用socket创建文件描述符2)调用connect,向服务器发送连接请求3)connect会发送一个请求SYN段并阻塞等待服务器应答(第一次握手)4)服务器收

TCP/IP模型及TCP/UDP协议

协议:为进行网络中的数据交换(通信)而建立的规则.标准或约定.(=语义+语法+规则) TCP/IP已成为Internet上通信的工业标准. TCP/IP模型: TCP协议是一个面向连接的可靠性传输协议,在发送数据之前,先要发出连接请求,当对方监听到有请求来到时就建立连接,然后双方就可以收发消息,发送完信息后,双方就断开连接(即三次握手协议). 三次握手协议: 第一次握手: 建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认:SYN:同步序列编号(Sy

Socket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)

ZERO.前言 有关通信原理内容是在网上或百科整理得到,代码部分为本人所写,如果不当,还望指教. 一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据.而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求. 那么,什么是s

Linux 下 简单客户端服务器通讯模型(TCP)

原文:Linux 下 简单客户端服务器通讯模型(TCP) 服务器端:server.c #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/socket.h> #include<sys/types.h> #include <stdio.h> #include <unistd.h> #inclu

网络编程TCP/IP与UDP实现客户端与客户端聊天

一.TCP/IP协议 既然是网络编程,涉及几个系统之间的交互,那么首先要考虑的是如何准确的定位到网络上的一台或几台主机,另一个是如何进行可靠高效的数据传输.这里就要使用到TCP/IP协议. TCP/IP协议(传输控制协议)由网络层的IP协议和传输层的TCP协议组成.IP层负责网络主机的定位,数据传输的路由,由IP地址可以唯一的确定Internet上的一台主机.TCP层负责面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象. 二.TCP与UDP TCP是一种面向连接的保证可靠传输的协议

java 通过TCP\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端

java 通过TCP\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端 启动界面如下图: 首先启动服务器: 客户端登陆,登陆成功后为: 默认发送是全部用户,是多人发送. 当在边列表里面选择了用户后,可以与此用户建立点对点链接进行聊天,可以发送文件. 用户在线离线状态会实时更新,如果离线,则存为离线消息.当下次上线的时候,会接受到离线消息 从一个用户接受文件的同时,还可以接受从服务器发过来的文件 接受文件完成后,显示记录,并显示保存目录 消息发送演示 服务器端代码: 1 im