计算机网络是通过传输介质、通信设施和网络通信协议,把各种网络设备互相连接起来,实现资源共享和数据传输的系统。网络编程是实现互联网上的多个设备之间进行数据传输
网络协议是用来规定数据传输的规则,为了统一网络传输的标准,国际标准化组织定义了OSI模型(开放系统互联参考模型),但由于OSI模型的协议比较复杂,所以并没有得到广泛的应用,而在实际应用中一般采用TCP/IP模型。
ip地址
端口号
端口分类:
公有端口 0~1023
HTTP : 80
HTTPS : 443
FTP : 21
Telent : 23
程序注册端口:1024~49151 分配用户或者程序
tomcat:8080
mysql:3306
Orcal:1521
动态、私有端口: 49152~65535
好比你要去某地找某个人,需要知道地址(具体到单元楼)和门牌号。
TCP协议提供IP环境下数据可靠传输,通过面向连接、端对端和可靠的数据包进行传输。即它是事先为所发送的数据建立好连接通道,然后在进行数据发送。
三次握手过程说明:
第一次握手:Client发送标志位(位码) syn(建立联机)=1 随机产生序列号seq=100的数据发送给Server,Server收到syn=1则知道Client要求建立联机。
第二次握手:Server收到Client请求后确认联机信息,向Client发送ack(确认信号)=(Client的seqno+1),syn=1,随机产生序列号seqno=100的数据发送给Client。
第二次握手:Client收到ack后检查是否正确,若正确,Client再次发送ack=(Server的seq+1),Server确认后则表明连接成功。
举一个不怎么恰当的例子例:
例如跑步比赛:将发送指令的作为客户端,参赛者为服务器
则: 预备 是客户端发送给服务器的第一次握手
运动员准备好了的信息 是服务端发送给客户端的第二次握手信息
跑: 是客户端发送给服务器的第三次握手
TCP连接因为是全双工的,因此单方面断开连接是不够的。断开了发送,并不能保证不会进行接收,因此需要客户端和服务端双方都有断开连接的动作
第一次挥手:
当数据传输即将完成,Client向服务端发送Fin(结束信号)=1的请求关闭标志位,代表告诉Server,Client数据传输完成,准备关闭连接
第二次挥手:
Server收到FIN后,Server先发送一个ACK信号给Client,确认序号为收到的序列号+1,表达的意思为你方的请求关闭我方已收到,但我方还有数据传输未完成,待我传输完成再告诉你。
第三次挥手:
Server数据传输完成,向Client发送Fin=1,Client收到Server发送的Fin=1时,知道Server的数据传输完成,可以断开连接。
第四次挥手:Client收到Server发送的Fin=1后,向Server发送ack信号确认信息进行确认,同时把自身状态设置为time_wait状态,启动计时器。如果Server没有收到Clent发送的ack,则在计时器结束后会要求客户端再发送一次ack,当Server收到Client的ack后,Server断开连接。Client在2MLS(2倍报文最大生存时间)后没有收到Server发送的重传ack请求,则认为服务端已接收到了客户端的ack,Client断开连接。
举一个不怎么恰当的例子例:
例如男女朋友吵架:
则: 女:我们分手吧 是客户端发送给服务器的第一次挥手信息
男:嗯 好吧! 是服务端发送给客户端的第二次挥手信息
男:那我们分手吧 是服务端发送给客户端的第三次挥手信息
女: 嗯 再见! 是客户端发送给服务器的第四次挥手信息
UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。
UDP | TCP | |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠 | 可靠 |
连接对象个数 | 支持一对一、一对多、多对多和多对一交互通信 | 只能一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
使用场景 | 使用与实时应用(IP电话、视频会议、直播等) | 适用于要求可靠传输的应用。例如文件传输 |
java.net包中包含的类和接口,提供了低层次的通信细节
此类表示Internet协议(IP)地址。
IP地址是由IP使用的32位或128位无符号数字,构建UDP和TCP协议的低级协议。
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressTest {
public static void main(String[] args) {
try {
//查询本机ip地址
InetAddress local_ip = InetAddress.getByName("localhost");
System.out.println(local_ip);
local_ip = InetAddress.getByName("127.0.0.1");
System.out.println(local_ip);
System.out.println(InetAddress.getByName("liang-PC"));
System.out.println(InetAddress.getLocalHost());
InetAddress baidu_ip = InetAddress.getByName("www.baidu.com");//查询网站ip地址
System.out.println(baidu_ip);
System.out.println(baidu_ip.getAddress());//InetAddress对象的原始IP地址
System.out.println(baidu_ip.getHostName());//获取此IP地址的主机名。
System.out.println(baidu_ip.getHostAddress());//返回文本显示中的IP地址字符串。
System.out.println(baidu_ip.getCanonicalHostName());//获取此IP地址的完全限定域名。
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
该类实现IP套接字地址(IP地址+端口号)它也可以是一对(主机名+端口号)
import java.net.InetSocketAddress;
public class InetSocketAddressTest {
public static void main(String[] args) {
//该类实现IP套接字地址(IP地址+端口号)它也可以是一对(主机名+端口号),在这种情况下将尝试解析主机名。
InetSocketAddress inetSocket = new InetSocketAddress("127.0.0.1", 8080);
System.out.println(inetSocket);
System.out.println(inetSocket.getAddress());//获得 InetAddress
System.out.println(inetSocket.getHostName());//
System.out.println(inetSocket.getHostString());//地址
System.out.println(inetSocket.getPort());//端口
}
}
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @deprecated : 服务器端
* @author liang
*/
public class TcpServerDemo {
public static void main(String[] args) {
ServerSocket serverSocket = null;//服务器套接字
Socket socket = null;
InputStream inputStream = null;
try {
serverSocket = new ServerSocket(8888);//创建绑定到指定端口的服务器套接字
socket = serverSocket.accept();//侦听要连接到此套接字并接受它。 该方法将阻塞直到建立连接。
inputStream = socket.getInputStream();//获取该套接字的输入流
//接收流数据
byte[] bytes = new byte[1024];
int len = 0;
while ((len = inputStream.read(bytes)) != -1){
String str = new String(bytes,0,len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭流
if (inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭套接字
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭服务器套接字
if (serverSocket != null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* @deprecated : 客户端
* @author liang
*/
public class TcpClientDemo {
public static void main(String[] args) {
Socket client = null;
OutputStream outputStream = null;
try {
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
int port =8888;
//创建流套接字并将其连接到指定IP地址的指定端口号
client = new Socket(inetAddress,port);
//获取该套接字的输出流
outputStream = client.getOutputStream();
//创建Scanner套接字
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String line = scanner.nextLine();//获取输入行数据
//将数据写入输出流
outputStream.write(line.getBytes(),0,line.getBytes().length);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭输出流
if (outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭客户端套接字
if (client!=null){
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class FileServer {
public static void main(String[] args) {
ServerSocket serverSocket = null;//服务器套接字
Socket socket = null;//套接字
InputStream inputStream = null;//输入流
FileOutputStream fileOutputStream = null;//文件输出流
OutputStream outputStream = null;//输出流
try {
serverSocket = new ServerSocket(8888);//创建绑定到指定端口的服务器套接字
socket = serverSocket.accept();//侦听要连接到此套接字并接受它。 该方法将阻塞直到建立连接。
inputStream = socket.getInputStream();//获取该套接字的输入流
fileOutputStream = new FileOutputStream(new File("rec.jpg"));//创建文件输出流
//读取输入流数据 并写入文件输出流
byte[] buff = new byte[1024];
int len = 0;
while ((len = inputStream.read(buff)) != -1){
fileOutputStream.write(buff,0,len);
}
//获取该套接字的输出流
outputStream = socket.getOutputStream();
outputStream.write("接收完毕,可以断开了".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
if (outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (serverSocket != null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class FileClient {
public static void main(String[] args) {
Socket socket = null;
FileInputStream fileInputStream = null;
OutputStream outputStream = null;
InputStream inputStream = null;
try {
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
int port = 8888;
socket = new Socket(inetAddress,port);//创建流套接字并将其连接到指定IP地址的指定端口号
outputStream = socket.getOutputStream();//获取该套接字的输出流
fileInputStream = new FileInputStream(new File("Hydrangeas.jpg"));//创建文件输入流
//读取文件输入流数据,并写入输出流
byte[] buff = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(buff)) != -1){
outputStream.write(buff,0,len);
}
/*
在客户端或者服务端通过socket.shutdownOutput()都是单向关闭的,即关闭客户端的输出流并不会关闭服务端的输出流,所以是一种单方向的关闭流;
通过socket.shutdownOutput()关闭输出流,但socket仍然是连接状态,连接并未关闭
如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket
*/
//通知服务器 我数据输出完毕
socket.shutdownOutput();//关闭客户端输出流
//获取该套接字的输入流
inputStream = socket.getInputStream();
len = 0;
//接收并打印输入流数据
while ((len = inputStream.read(buff)) != -1){
String str = new String(buff,0,len);
System.out.println(str);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileInputStream != null){
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class UdpSocket1 {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
//DatagramSocket表示用于发送和接收数据报数据包的套接字。
datagramSocket = new DatagramSocket(8888);
String str = "我是UDP传输端1";
//DatagramPacket表示数据报包,数据报包用于实现无连接分组传送服务。
DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(),0,str.getBytes().length, InetAddress.getByName("127.0.0.1"),9999);
datagramSocket.send(datagramPacket);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (datagramSocket != null){
datagramSocket.close();
}
}
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpSocket2 {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
//创建数据报套接字
datagramSocket = new DatagramSocket(9999);
//接收数据包
byte[] buff = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buff,0,buff.length);
datagramSocket.receive(datagramPacket);//阻塞式接收
System.out.println(datagramPacket.getAddress());
System.out.println(datagramPacket.getPort());
System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength() ));
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (datagramSocket != null){
datagramSocket.close();
}
}
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;
public class TalkSend implements Runnable {
int partFrom = 0;//接收端 端口
int partTo = 0;//发送到 端口
String ipTo = null;//发送到ip
public TalkSend(int partFrom,int partTo, String ipTo){
this.ipTo = ipTo;
this.partFrom = partFrom;
this.partTo = partTo;
}
@Override
public void run() {
DatagramSocket datagramSocket = null;
try {
//DatagramSocket表示用于发送和接收数据报数据包的套接字。
datagramSocket = new DatagramSocket(partFrom);
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String line = scanner.nextLine();
DatagramPacket datagramPacket = new DatagramPacket(line.getBytes(),0,line.getBytes().length, InetAddress.getByName(ipTo),partTo);
datagramSocket.send(datagramPacket);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (datagramSocket != null){
datagramSocket.close();
}
}
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class TalkRec implements Runnable {
int partFrom = 0;//接收端 端口
public TalkRec(int partFrom){
this.partFrom = partFrom;
}
@Override
public void run() {
DatagramSocket datagramSocket = null;
try {
//创建数据报套接字
datagramSocket = new DatagramSocket(partFrom);
while (true) {
//接收数据包
byte[] buff = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buff, 0, buff.length);
datagramSocket.receive(datagramPacket);//阻塞式接收
System.out.println(datagramPacket.getAddress()+":"+datagramPacket.getPort()+" : "+new String(datagramPacket.getData(), 0, datagramPacket.getLength()));
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (datagramSocket != null){
datagramSocket.close();
}
}
}
}
public class Talk1 {
public static void main(String[] args) {
new Thread(new TalkSend(7777,9999,"127.0.0.1")).start();
new Thread(new TalkRec(8888)).start();
}
}
public class Talk2 {
public static void main(String[] args) {
new Thread(new TalkSend(5555,8888,"127.0.0.1")).start();
new Thread(new TalkRec(9999)).start();
}
}
用于定位资源。在WWW上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位器),它是WWW的统一资源定位标志,就是指网络地址。
协议://主机:端口/项目名/资源文件名
import java.net.MalformedURLException;
import java.net.URL;
public class URLTest {
public static void main(String[] args) {
try {
URL url = new URL("https://editor.csdn.net/md?articleId=110088434");
System.out.println(url.getPath());//文件名
System.out.println(url.getHost());//主机名
System.out.println(url.getProtocol());//协议
System.out.println(url.getFile());//全路径
System.out.println(url.getQuery());//参数 键值对
System.out.println(url.getPort());//端口号
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
public class UrlDownload {
public static void main(String[] args) {
InputStream in = null;
FileOutputStream fileOutputStream = null;
try {
URL url = new URL("https://m701.music.126.net/20201125215637/9b70b42b383bf399d5a7d3f2aee8b941/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/4903215562/5bfc/fbd2/fa38/adfd6bf3d0fb529fb2681943d6065842.m4a");
URLConnection urlConnection = url.openConnection();
in = urlConnection.getInputStream();
fileOutputStream = new FileOutputStream(new File("5842.m4a"));
byte[] buff = new byte[1024];
int len = 0;
while ((len = in.read(buff)) != -1){
fileOutputStream.write(buff,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}