文章目录
一、前言为什么需要网络编程? 二、网络编程是什么?三、网络编程的基本概念3.1发送端和接收端3.2请求和响应3.3服务器和客户端 四、常见的服务端客户端模型五、Socket套接字5.1概念5.2分类 六、数据报套接字通信模型七、Java流套接字通信模型八、UDP数据报套接字API介绍 九、TCP流套接字API介绍
一、前言
在本文中,会介绍一些关于网络编程的基础知识Socket的一些api会在文章末尾运用所讲知识做一个基于网络的回显的代码
为什么需要网络编程?
当你打开CSDN看到这篇文章时,实质上是通过网络来获取一个文本资源、图片资源等等
和本地硬盘上打开一个文本一样,只不过这个文本资源是来自于网络。
和本地资源来说,网络提供了更多更丰富的资源。
所谓的网络资源,就是在网络中可以获取到的各种资源。
而所有的网络资源,都是通过网络编程来传输的。
二、网络编程是什么?
网络编程,是指网络上的主机,通过不同的进程,以编程的方式来实现网络传输(实现网络数据传输)
这里只需要满足不同进程就可以,因为在大多数的情况下,都是在同一个主机上,通过网络编程来传输数据。
三、网络编程的基本概念
3.1发送端和接收端
在⼀次⽹络数据传输时:
发送端: 数据的发送⽅进程,称为发送端。发送端主机即⽹络通信中的源主机。
接收端: 数据的接收⽅进程,称为接收端。接收端主机即⽹络通信中的⽬的主机。
收发端: 发送端和接收端两端,也简称为收发端。
注意:发送端和接收端是相对的,只是一次网络数据传输产生数据流向后的概念。
3.2请求和响应
一般来说,获取一个网络资源,一般需要两次网络数据传输。
第一次:请求数据的发送第二次:响应数据的发送3.3服务器和客户端
服务端: 在网络传输中,提供服务的一方进程,成为服务端。也可以向外提供服务
客户端: 获取服务的一方进程,称为客户端。
四、常见的服务端客户端模型
一般来说,网络数据的传输的过程如下
客户端:输入请求,将请求发送到服务端服务端:接收请求,分析请求内容服务端:根据请求内容执行响应的业务服务端:将执行业务的结果作为响应返回给客户端客户端:根据服务端的响应,将响应展示出来五、Socket套接字
5.1概念
Socket套接字,是由系统提供⽤于⽹络通信的技术,是基于TCP/IP协议的⽹络通信的基本操作单元。
基于Socket套接字的⽹络程序开发就是⽹络编程。
5.2分类
Socket套接字主要针对传输层协议分为三类:
流套接字流套接字: 使用传输层Tcp协议
TCP,即Transmission Control Protocol(传输控制协议),传输层协议。
下一位Tcp的特点 有连接可靠传输面向字节流有接收缓冲区,也有发送缓冲区大小不限
对于字节流来说,可以简单的理解为,传输数据是基于IO流,流式数据的特征就是在IO流没有关闭的情况下,是⽆边界的数据,可以多次发送,也可以分开多次接收。
2. 数据报套接字
数据报套接字: 使⽤传输层UDP协议
UDP,即User Datagram Protocol(⽤⼾数据报协议),传输层协议。
以下为UDP的特点:
对于数据报来说,可以简单的理解为,传输数据是⼀块⼀块的,发送⼀块数据假如100个字节,必须⼀次发送,接收也必须⼀次接收100个字节,⽽不能分100次,每次接收1个字节。
3. 原始套接字
原始套接字⽤于⾃定义传输层协议,⽤于读写内核没有处理的IP协议数据。
六、数据报套接字通信模型
对于UDP协议来说,具有⽆连接,⾯向数据报的特征,即每次都是没有建⽴连接,并且⼀次发送全部数据报,⼀次接收全部的数据报。
java中使⽤UDP协议通信,主要基于 DatagramSocket 类来创建数据报套接字,并使⽤DatagramPacket 作为发送或接收的UDP数据报。对于⼀次发送及接收UDP数据报的流程如下:
七、Java流套接字通信模型
八、UDP数据报套接字
API介绍
DatagramSocket
DatagramSocket
是UDP Socket,⽤于发送和接收UDP数据报。
方法签名 | 方法说明 |
---|---|
DatagramSocket() | 创建⼀个UDP数据报套接字的Socket,绑定到本机任意⼀个随机端⼝(⼀般⽤于客⼾端) |
DatagramSocket(int port) | 创建⼀个UDP数据报套接字的Socket,绑定到本机指定的端⼝(⼀般⽤于服务端) |
DatagramSocket
⽅法:
方法签名 | 方法说明 |
---|---|
void receive(DatagramPacket p) | 从此套接字接收数据报(如果没有接收到数据报,该⽅法会阻塞等待) |
void send(DatagramPacket p) | 从此套接字发送数据报包(不会阻塞等待,直接发送) |
void close() | 关闭此数据报套接字 |
DatagramPacket
DatagramPacket
是UDP Socket发送和接收的数据报。
DatagramPacket
构造⽅法:
方法签名 | 方法说明 |
---|---|
DatagramPacket(byte[] buf, int length) | 构造⼀个DatagramPacket以⽤来接收数据报,接收的数据保存在字节数组(第⼀个参数buf)中,接收指定⻓度(第⼆个参数length) |
DatagramPacket(byte[] buf, int offset, int length | 构造⼀个DatagramPacket以⽤来发送数据报,发送的数据为字节数组(第⼀个参数buf)中,从0到指定⻓度(第⼆个参数length)。address指定⽬的主机的IP和端⼝号 |
DatagramPacket
⽅法:
方法签名 | 方法说明 |
---|---|
InetAddress getAddress() | 从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址 |
int getPort() | 从从接收的数据报中,获取发送端主机的端⼝号;或从发送的数据报中,获取接收端主机端⼝号 |
byte[] getData() | 获取数据报中的数据 |
构造UDP发送的数据报时,需要传⼊ SocketAddress
,该对象可以使⽤ InetSocketAddress
来创建。
InetSocketAddress
InetSocketAddress
( SocketAddress
的⼦类 )构造⽅法:
方法签名 | 方法说明 |
---|---|
InetSocketAddress(InetAddress addr, int port) | 创建⼀个Socket地址,包含IP地址和端⼝号 |
利用UDP数据报创建一个回显客户端和服务器
public class UdpEchoClient { private DatagramSocket socket = null; private String serverIp; private int serverPort; public UdpEchoClient(String serverIp,int serverPort) throws SocketException { socket = new DatagramSocket(); this.serverIp = serverIp; this.serverPort = serverPort; } public void start() throws IOException { System.out.println("客户端启动!!!"); Scanner scanner = new Scanner(System.in); while (true){ System.out.println("请输入你的请求!!!"); String request = scanner.next(); //打包成数据包 通过网卡发送到服务端 DatagramPacket requestPackage = new DatagramPacket(request.getBytes(),0,request.getBytes().length, InetAddress.getByName(serverIp),serverPort); socket.send(requestPackage); DatagramPacket responsePackage = new DatagramPacket(new byte[4096],4096); socket.receive(responsePackage); String response = new String(responsePackage.getData(),0,responsePackage.getLength()); System.out.println(response); } } public static void main(String[] args) throws IOException { UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090); client.start(); }
public abstract class UdpEchoServer { private DatagramSocket socket = null; public UdpEchoServer(int port) throws SocketException { socket = new DatagramSocket(port); } public void start() throws IOException { System.out.println("服务器启动!!!"); //接收请求 while (true){ DatagramPacket requestPackage = new DatagramPacket(new byte[4096],4096); socket.receive(requestPackage); //处理请求 String request = new String(requestPackage.getData(),0,requestPackage.getLength()); String response = process(request); //返回响应 DatagramPacket responsePackage = new DatagramPacket(response.getBytes(),0,response.getBytes().length, requestPackage.getSocketAddress()); socket.send(responsePackage); System.out.printf("[%s:%d] req=%s res=%s\n",requestPackage.getAddress(),requestPackage.getPort(),request,response); } } public String process(String request) { return request; } public static void main(String[] args) throws IOException { UdpEchoServer server = new UdpDictServer(9090); server.start(); }}
运行效果如下
一个简易的字典
public class UdpDictServer extends UdpEchoServer{ private HashMap<String,String> hashMap = null; public UdpDictServer(int port) throws SocketException { super(port); hashMap = new HashMap<>(); hashMap.put("hello","你好" ); hashMap.put("dog","小狗" ); hashMap.put("cat","小猫" ); hashMap.put("world","世界" ); hashMap.put("baby","宝贝" ); } @Override public String process(String request){ return hashMap.getOrDefault(request,"没有找到该词汇"); } public static void main(String[] args) throws IOException { UdpDictServer dictServer = new UdpDictServer(9090); dictServer.start(); }}
九、TCP流套接字
API介绍
ServerSocket
ServerSocket
是创建TCP服务端Socket的API。
ServerSocket
构造⽅法:
方法签名 | 方法说明 |
---|---|
ServerSocket(int port) | 创建⼀个服务端流套接字Socket,并绑定到指定端⼝ |
ServerSocket
⽅法:
方法签名 | 方法说明 |
---|---|
Socket accept() | 开始监听指定端⼝(创建时绑定的端⼝),有客⼾端连接后,返回⼀个服务端Socket对象,并基于该Socket建⽴与客⼾端的连接,否则阻塞等待 |
void close() | 关闭此套接字 |
Socket
Socket
是客⼾端Socket,或服务端中接收到客⼾端建⽴连接(accept⽅法)的请求后,返回的服务端Socket。
不管是客⼾端还是服务端Socket,都是双⽅建⽴连接以后,保存的对端信息,及⽤来与对⽅收发数据的。
Socket
构造⽅法
方法签名 | 方法说明 |
---|---|
Socket(String host, int port) | 创建⼀个客⼾端流套接字Socket,并与对应IP的主机上,对应端⼝的进程建⽴连接 |
Socket
⽅法:
方法签名 | 方法说明 |
---|---|
InetAddress getInetAddress() | 返回套接字所连接的地址 |
InputStream getInputStream() | 返回此套接字的输⼊流 |
OutputStream getOutputStream() | 返回此套接字的输出流 |
public class TcpEchoServer { private ServerSocket serverSocket = null; public TcpEchoServer(int port) throws IOException { serverSocket = new ServerSocket(port); } public void start() throws IOException { System.out.println("服务端启动!!!");// ExecutorService pool = Executors.newCachedThreadPool(); while (true){ Socket clientSocket = serverSocket.accept(); Thread t = new Thread(()->{ try { processConnection(clientSocket); } catch (IOException e) { throw new RuntimeException(e); } }); t.start(); } } private void processConnection(Socket clientSocket) throws IOException { System.out.printf("[%s:%d] 客户端上线\n",clientSocket.getInetAddress(),clientSocket.getPort()); try (InputStream inputStream = clientSocket.getInputStream(); OutputStream outputStream = clientSocket.getOutputStream()){ Scanner scanner = new Scanner(inputStream); while (true){ if (!scanner.hasNext()){ System.out.printf("[%s:%d] 客户端下线\n",clientSocket.getInetAddress(),clientSocket.getPort()); break; } String request = scanner.next(); String response = process(request); outputStream.write(response.getBytes(),0,response.getBytes().length); System.out.printf("[%s:%d] req=%s res=%s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response); } } catch (IOException e) { throw new RuntimeException(e); } } public String process(String request) { return request +"\n"; } public static void main(String[] args) throws IOException { TcpEchoServer server = new TcpEchoServer(9090); server.start(); }}
public class TcpEchoClient { private Socket socket = null; public TcpEchoClient(String serverIp,int serverPort) throws IOException { socket = new Socket(serverIp,serverPort); } public void start(){ System.out.println("客户端启动!"); Scanner scanner = new Scanner(System.in); try (InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream()){ Scanner scannerNetwork = new Scanner(inputStream); while (true){ System.out.println("输入你的请求-》"); String request = scanner.next(); request +="\n"; outputStream.write(request.getBytes()); if (!scannerNetwork.hasNext()){ break; } String response = scannerNetwork.next(); System.out.println(response); } } catch (IOException e) { throw new RuntimeException(e); } } public static void main(String[] args) throws IOException { TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090); client.start(); }}
运行效果展示
以上就是本文所有内容,如果对你有帮助的话,点赞收藏支持一下吧!???