Java网络编程技术TCP和UDP
网络编程概述
网络编程就是两个或多个设备之间的数据交换,其实更具体的说,网络编程就是两个或多个程序之间的数据交换,和普通的单机程序相比,网络程序最大的不同就是需要交换数据的程序运行在不同的计算机上,这样就造成了数据交换的复杂 。
网络通讯的过程网络通讯基于“请求-响应”模型
- C/S结构
- B/S结构
- P2P程序
- 协议(Protocol)网络编程中最重要,也是最复杂的概念
在现有的网络中,网络通讯的方式主要有两种
- TCP(传输控制协议)方式
- UDP(用户数据报协议)方式
在网络通讯中,TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据。而UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户端无法获得 。
这两种传输方式都是实际的网络编程中进行使用,重要的数据一般使用TCP方式进行数据传输,而大量的非核心数据则都通过UDP方式进行传递,在一些程序中甚至结合使用这两种方式进行数据的传递 。
TCP需要建立专用的虚拟连接以及确认传输是否正确,所以使用TCP方式的速度稍微慢一些,而且传输时产生的数据量要比UDP稍微大一些 。
UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。 由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输,例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。 但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议 。
TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。第一次握手,客户端向服务器端发出连接请求,等待服务器确认,第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求,第三次握手,客户端再次向服务器端发送确认信息,确认连接 。
由于TCP协议的面向连接特性,它可以保证传输数据的安全性,所以是一个被广泛采用的协议,例如在下载文件时,如果数据接收不完整,将会导致文件数据丢失而不能被打开,因此,下载文件时必须采用TCP协议 。
网络编程步骤
客户端网络编程步骤
客户端(Client)是指网络编程中首先发起连接的程序,客户端一般实现程序界面和基本逻辑实现,在进行实际的客户端编程时,无论客户端复杂还是简单,以及客户端实现的方式,客户端的编程主要由三个步骤实现
建立网络连接
客户端网络编程的第一步都是建立网络连接。在建立网络连接时需要指定连接到的服务器的IP地址和端口号,建立完成以后,会形成一条虚拟的连接,后续的操作就可以通过该连接实现数据交换了
交换数据
连接建立以后,就可以通过这个连接交换数据了。交换数据严格按照请求响应模型进行,由客户端发送一个请求数据到服务器,服务器反馈一个响应数据给客户端,如果客户端不发送请求则服务器端就不响应。 根据逻辑需要,可以多次交换数据,但是还是必须遵循请求响应模型 。
关闭网络连接
在数据交换完成以后,关闭网络连接,释放程序占用的端口、内存等系统资源,结束网络编程 。
服务端网络编程步骤
服务器端(Server)是指在网络编程中被动等待连接的程序,服务器端一般实现程序的核心逻辑以及数据存储等核心功能。服务器端的编程步骤和客户端不同,是由四个步骤实现,依次是
监听端口
服务器端属于被动等待连接,所以服务器端启动以后,不需要发起连接,而只需要监听本地计算机的某个固定端口即可 这个端口就是服务器端开放给客户端的端口,服务器端程序运行的本地计算机的IP地址就是服务器端程序的IP地址 。
获得连接
当客户端连接到服务器端时,服务器端就可以获得一个连接,这个连接包含客户端的信息,例如客户端IP地址等等,服务器端和客户端也通过该连接进行数据交换 一般在服务器端编程中,当获得连接时,需要开启专门的线程处理该连接,每个连接都由独立的线程实现 。
交换数据
服务器端通过获得的连接进行数据交换。服务器端的数据交换步骤是首先接收客户端发送过来的数据,然后进行逻辑处理,再把处理以后的结果数据发送给客户端。简单来说,就是先接收再发送,这个和客户端的数据交换数序不同 其实,服务器端获得的连接和客户端连接是一样的,只是数据交换的步骤不同 。
关闭连接
当服务器程序关闭时,需要关闭服务器端,通过关闭服务器端使得服务器监听的端口以及占用的内存可以释放出来,实现了连接的关闭
Java网络编程技术
网络类——InetAddress类
public class IPDemo {
public static void main(String[] args) {
try {
InetAddress inetAddress = InetAddress.getLocalHost();
System.out.println(inetAddress.toString());
System.out.println(inetAddress.getHostAddress());
System.out.println(inetAddress.getHostName());
InetAddress ia = InetAddress.getByName("localhost");
System.out.println(ia.getHostAddress());
System.out.println(ia.getHostName());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
UDP编程
UDP发送端
步骤
1、建立udpsocket服务
2、提供数据,并将数据封装到数据包中
3、通过socket服务的发送功能将数据包发送出去
4、关闭资源
public class UdpSend {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
// 1、创建udp服务,通过DatagramSocket对象
datagramSocket = new DatagramSocket(8888);
// 2、确定数据,并封装到数据包
byte[] data = “Hello everyone,,guys".getBytes();
DatagramPacket datagramPacket = new DatagramPacket(data, data.length, InetAddress.getByName("192.168.50.35"), 9999);
//3、通过socket服务,将已有的数据包发送出去
datagramSocket.send(datagramPacket);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 4、关闭资源
if (datagramSocket != null) {
datagramSocket.close();
}
}
}
}
UDP接收端
步骤
1、定义udpsocket服务,通常会监听一个端口
2、定义数据包,因为要存储接收到的数据,数据包中有更多的功能可以提取字节数据中不同的数据信息
3、通过receive方法将接收的到的数据存入已定义好的数据包中
4、通过数据包对象特有的功能,将数据取出
5、关闭资源
public class UdpReceive {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
datagramSocket = new DatagramSocket(9999);
// 2、定义数据包用于存储数据
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
// 3、通过服务的receive方法将受到的数据存入数据包中
datagramSocket.receive(datagramPacket); // 阻塞式方法
// 4、通过数据包的方法获取数据包中的数据
String ip = datagramPacket.getAddress().getHostAddress().toString(); // 获取地址
String data = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
int port = datagramPacket.getPort();
System.out.println(ip + "::" + data + "::" + port);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (datagramSocket != null) {
datagramSocket.close();
}
}
}
}
UDP键盘录入
public class UdpSend02 {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
// 1、创建udp服务,通过DatagramSocket对象
datagramSocket = new DatagramSocket(8888);
// 2、确定数据,并封装到数据包
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = bufr.readLine()) != null) {
if ("bye".equals(line)) {
break;
}
byte[] data = line.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(data, data.length, InetAddress.getByName("192.168.50.35"), 10000);
//3、通过socket服务,将已有的数据包发送出去
datagramSocket.send(datagramPacket);
}
}
}
}
UDP聊天
public class Send implements Runnable {
private DatagramSocket datagramSocket;
public Send(DatagramSocket datagramSocket) {
this.datagramSocket = datagramSocket;
}
@Override
public void run() {
try {
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = bufr.readLine()) != null) {
byte[] data = line.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(data, data.length, InetAddress.getByName("192.168.50.255"), 10000);
datagramSocket.send(datagramPacket);
if ("bye".equals(line)) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Receive implements Runnable {
private DatagramSocket datagramSocket;
public Receive(DatagramSocket datagramSocket) {
this.datagramSocket = datagramSocket;
}
@Override
public void run() {
try {
while (true) {
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
datagramSocket.receive(datagramPacket);
String ip = datagramPacket.getAddress().getHostAddress();
String data = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
System.out.println(ip + ">>>:" + data);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ChatDemo {
public static void main(String[] args) {
try {
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receiveSocket = new DatagramSocket(10000);
new Thread(new Send(sendSocket)).start();
new Thread(new Receive(receiveSocket)).start();
} catch (SocketException e) {
e.printStackTrace();
}
}
}
TCP编程
这里举例一个图片上传的案例
public class TcpClient05 {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 8888);
// 获取流对象
FileInputStream fis = new FileInputStream(new File("C:\\Users\\chend\\Pictures\\picture\\washing.jpg"));
OutputStream out = socket.getOutputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int len = 0;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
socket.shutdownOutput();
String result = in.readLine();
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class TcpServer05 {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();
// 获取流对象
InputStream in = socket.getInputStream();
FileOutputStream fos = new FileOutputStream(new File("E:\\DingLi\\1912.jpg"));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
int len = 0;
byte[] bytes = new byte[1024];
while ((len = in.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
out.println("图片上传成功!");
} catch (IOException e) {
throw new RuntimeException("图片上传失败!");
}
}
}
关于java的网络编程就说到这里了,如有不足之处,欢迎指正!
感恩能与大家在华为云遇见!希望能与大家一起在华为云社区共同成长。
- 点赞
- 收藏
- 关注作者
评论(0)