网络通信的基础知识
- IP:
- IP是 Interent Protocol(国际互连协议的缩写),是TCP/IP协议中的网络层协议。
- 想要让网络中的计算机实现通信,那么每个计算机必须有一个标识号,通过标识号来指定要接受信息的计算机以及要发送信息的计算机,这个标识号就是IP地址。(通俗的理解就如同生活中的手机号码)
- IP地址的格式为xxx.xxx.xxx.xxx是很难记忆的,因此,我们会把IP地址转化为域名地址,方便记忆。
- 本机IP地址为:127.0.0.1或localhost
- 端口:
- 我们知道计算机中由很多的进程,不同的进程需要不同的网络资源,那么就需要为每个进程分配固定的端口号。
- 端口号的范围是:0-65535
- 总结:要实现网络通信必须知道对方的IP地址以及端口号。
TCP和UDP
- TCP(传输控制协议):
- TCP协议是一种***面向连接、可靠的、基于字节流***的传输层通信协议。
- UDP(用户数据报协议):
- UDP协议是一种支持无连接的传输协议,它为应用程序提供了一种无需创建链接就可以发送数据报的方法。
- TCP和UDP的区别:
- TCP是面向连接的,效率低;UDP不需要连接,速度快
- TCP只能一对一的传输;UDP可以一对一、一对多、多对多、多对一的传输
- TCP保证传输数据的正确性、有序性、不丢包、不重复;UDP不保证可靠性
- TCP适合网络负担不大,可靠性要求高的场所;UDP适合网络负担重、响应高、客户端较多、可靠性要求不高的场景
Java中使用TCP协议进行传输
- Java中要使用TCP传输就要使用socket套接字
- socket套接字:具有唯一标识的IP地址和端口号
- socket的原理机制:
- 网络中的通信实际上是socket间的通信
- 通信的两端计算机都有socket
- 数据在两个socket之间通过IO流进行传输
- socket传输的图解:
- TCP传输的步骤:
- 建立客户端和服务器端,客户端使用Socket,服务器端使用ServerSocket
- 建立socket连接后使用IO流进行传输,客户端使用传出流,服务器端使用写入流接收,然后再使用管道流查看数据
- 在传输完数据后要关闭所有的IO流以及socket
- 启动时要先启动服务器端,再启动客户端
- 演示客户端给服务器端发送信息:
客户端:
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class Clicent {
public static void main(String[] args) throws Exception {
//建立socket连接
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 6666);
String msg = "你好,服务器!";
//客户端给服务器端发送数据,那么就要读取客户端的数据,所以使用out
OutputStream out = socket.getOutputStream();
//tcp中的数据都是字节形式的
out.write(msg.getBytes(),0,msg.getBytes().length);
//关闭所有的流
out.close();
socket.close();
}
}
===========================================
服务器端:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//服务器端使用serversocket
ServerSocket serverSocket = new ServerSocket(6666);
//再使用accept方法来取得socket
Socket socket = serverSocket.accept();
InputStream in = socket.getInputStream();
int len;
byte[] bytes = new byte[1024];
//使用管道流来查看数据
ByteArrayOutputStream out = new ByteArrayOutputStream();
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
}
System.out.println(out.toString());
//关闭所有的流
out.close();
in.close();
socket.close();
serverSocket.close();
}
}
客户端:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class ClicentFile {
public static void main(String[] args) throws Exception {
//使用socket进行连接
Socket socket = new Socket(InetAddress.getByName("localhost"), 5555);
//读取文件
FileInputStream file = new FileInputStream("test.txt");
OutputStream out = socket.getOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = file.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
//服务器端接收到文件后会给客户端一个反馈,先关闭输出流
socket.shutdownOutput();
//打开输入流读取服务器端的信息
InputStream in = socket.getInputStream();
//管道流读取
ByteArrayOutputStream stream = new ByteArrayOutputStream();
int len1;
byte[] bytes1 = new byte[1024];
while ((len1=in.read(bytes1))!=-1){
stream.write(bytes1,0,len1);
}
System.out.println(stream.toString());
//关闭流
out.close();
file.close();
stream.close();
in.close();
socket.close();
}
}
=================================
服务器端:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerFile {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(5555);
Socket socket = serverSocket.accept();
InputStream in = socket.getInputStream();
FileOutputStream out = new FileOutputStream("测试.txt");
int len;
byte[] bytes = new byte[1024];
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
}
//接收文件成功后给客户端一个反馈
OutputStream stream = socket.getOutputStream();
stream.write("我已经成功接收到文件!".getBytes());
//关闭流
out.close();
in.close();
stream.close();
socket.close();
serverSocket.close();
}
}
Java中使用UDP协议进行传输
- 使用UDP协议进行传输时,要使用DatagramSocket以及DatagramPacket
- 使用DatagramSocket获取socket套接字
- 使用DatagramPacket建立数据报
- 传输完信息后把所有的流关闭
- 发送端和接收端的演示:
发送端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpSend {
public static void main(String[] args) throws Exception {
//1--使用datagramsocket获取socket
DatagramSocket socket = new DatagramSocket();
//声明要发送的数据
String msg="这是UDP传输";
//声明数据报
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, InetAddress.getByName("127.0.0.1"), 2333);
//发送数据报
socket.send(packet);
//关闭流
socket.close();
}
}
===================================
接收端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpResive {
public static void main(String[] args) throws Exception {
//1--使用datagramsocket获取socket
DatagramSocket socket = new DatagramSocket(2333);
//创建一个字节数组及datagrampacket接收数据报
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
//使用socket接收数据报
socket.receive(packet);
//使用packet中的getdata方法读取数据
System.out.println(new String(packet.getData()));
//关闭流
socket.close();
}
}
URL-统一资源定位符
- URL是因特网的万维网服务程序上用于指定信息位置的表示方法。
- 使用URL下载资源的实现步骤:
- 声明一个URL对象,把资源所在的地址作为参数
- 使用openconnection打开连接
- 通过IO流来读写
- 关闭所有的流
- 通过URL下载网上资源的程序演示:
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class URLDown {
public static void main(String[] args) throws Exception {
//1--声明一个url对象
URL url = new URL("https://m10.music.126.net/20191203110348/27f448e1cd8fb89c7127d574eb6bfa67/yyaac/545a/0e0f/075c/c03b40b7be9e943eb5d006be88784114.m4a");
//2--使用url打开连接
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
//3--读取数据
InputStream in = urlConnection.getInputStream();
//4--将文件写出
FileOutputStream out = new FileOutputStream("C:\\Users\\Henry哼哼哼\\Desktop\\爱你不是两三天2.mp3");
int len;
byte[] bytes = new byte[1024];
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
}
//5--关闭所有的流
out.close();
in.close();
urlConnection.disconnect();
}
}
使用多线程发送数据
- 我们在这里要让双方都可以发收数据,且对网络要求低,对数据的准确性也要求低,所以使用UDP协议
- 代码演示:
发送端:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class Sender implements Runnable {
private int toPort;
private int fromPort;
DatagramSocket socket = null;
BufferedReader reader = null;
public Sender(int toPort, int fromPort) throws SocketException {
this.toPort = toPort;
this.fromPort = fromPort;
socket = new DatagramSocket(fromPort);
reader = new BufferedReader(new InputStreamReader(System.in));
}
@Override
public void run() {
while (true) {
try {
String msg = reader.readLine();
//声明数据报
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.length(), InetAddress.getByName("127.0.0.1"), toPort);
//发送数据报
socket.send(packet);
//如果发送的内容是bye,则退出传输
if (msg.equals("bye")) {
break;
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭流
socket.close();
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
接收端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class Resiver implements Runnable {
private int port;
private String name;
DatagramSocket socket=null;
public Resiver(int port, String name) throws SocketException {
this.port = port;
this.name = name;
socket=new DatagramSocket(port);
}
@Override
public void run() {
while (true) {
//使用datagramsocket获得socket
try {
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
socket.receive(packet);
byte[] data = packet.getData();
String msg = new String(data, 0, data.length);
System.out.println(name + ":" + msg);
if (msg.equals("bye")){
break;
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭流
}
}
两个用户端:
import java.net.SocketException;
public class Teacher {
public static void main(String[] args) throws SocketException {
new Thread(new Sender(2222,6666)).start();
new Thread(new Resiver(5555,"老师")).start();
}
}
==========================
import java.net.SocketException;
public class Teacher {
public static void main(String[] args) throws SocketException {
new Thread(new Sender(2222,6666)).start();
new Thread(new Resiver(5555,"老师")).start();
}
}