文章目录
网络编程
1.1 概述
计算机网络
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统
网络编程的作用
无线电台、传播交流信息、数据交换与通信
- 网络编程的需要:
- 如何准确定位网络上的一台主机:通过网络端口定位到计算机的某个资源
- 传输数据
1.2 网络通信的要素
- 通信双方的地址:
- ip
- 端口号
- 规则:网络通信的协议:
-
TCP/IP参考模型
-
互联网是网络的网络(internet),即把很多计算机网络连接起来,形成一个全球统一的互联网。
对某个特定的计算机网络来说,它可能使用网络协议ABC,而另一个计算机网络可能使用网络协议XYZ。如果计算机网络各自的通讯协议不统一,就没法把不同的网络连接起来形成互联网。因此,为了把计算机网络接入互联网,就必须使用TCP/IP协议。
TCP/IP协议泛指互联网协议,其中最重要的两个协议是TCP协议和IP协议。只有使用TCP/IP协议的计算机才能够联入互联网,使用其他网络协议(例如NetBIOS、AppleTalk协议等)是无法联入互联网的。
1.3 IP地址
IP地址:InetAddress
在互联网中,一个IP地址用于唯一标识一个网络接口(Network Interface)。一台联入互联网的计算机肯定有一个IP地址,但也可能有多个IP地址
IP地址分为IPv4和IPv6两种。IPv4采用32位地址,类似101.202.99.12
,而IPv6采用128位地址,类似2001:0DA8:100A:0000:0000:1020:F2F3:1428
。IPv4地址总共有232个(大约42亿),而IPv6地址则总共有2128个(大约340万亿亿亿亿),IPv4的地址目前已耗尽,而IPv6的地址是根本用不完的。
IP地址又分为公网IP地址和内网IP地址。**公网IP地址可以直接被访问,内网IP地址只能在内网访问。**内网IP地址类似于:
-
192.168.x.x
-
10.x.x.x
-
有一个特殊的IP地址,称之为本机地址,它总是
127.0.0.1
(localhost)
如果一台计算机只有一个网卡,并且接入了网络,那么,它有一个本机地址127.0.0.1
,还有一个IP地址,例如101.202.99.12
,可以通过这个IP地址接入网络。
public class TestInetAddress {
public static void main(String[] args) {
try {
//查询本机地址
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
System.out.println(inetAddress);
InetAddress inetAddress2 = InetAddress.getByName("localhost");
System.out.println(inetAddress2);
InetAddress inetAddress3 = InetAddress.getLocalHost();
System.out.println(inetAddress3);
System.out.println(inetAddress2.getCanonicalHostName());//获得规范的名字
System.out.println(inetAddress2.getHostAddress());//获得ip
System.out.println(inetAddress2.getHostName());//域名或本机名
//查询网站ip地址
InetAddress inetAddress1 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress1);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
小结
计算机网络的基本概念主要有:
- 计算机网络:由两台或更多计算机组成的网络;
- 互联网:连接网络的网络;
- IP地址:计算机的网络接口(通常是网卡)在网络中的唯一标识;
- 网关:负责连接多个网络,并在多个网络之间转发数据的计算机,通常是路由器或交换机;
- 网络协议:互联网使用TCP/IP协议,它泛指互联网协议簇;
- IP协议:一种分组交换传输协议;
- TCP协议:一种面向连接,可靠传输的协议;
- UDP协议:一种无连接,不可靠传输的协议。
1.4 端口
端口表示计算机上的一个程序的进程:
- 不同的进程有不同的端口号,用于区分软件
- 被规定0~65535
- 单个协议下端口不能相同
- 端口分类:
- 公有端口:
- HTTP:80
- HTTPS:443
- FTP:21
- Telent:23
- 程序注册端口:1024~49151(分配给用户或程序)
- Tomcat:8080
- MySQL:3306
- 动态、私有端口:49152~65535
- 公有端口:
netstat -ano #查看所有端口
netstat -ano|findstr "10033" #查看指定端口
tasklist|findstr "14944" #查看指定端口的进程
1.5 通信协议
TCP/IP协议簇:
- TCP:用户传输协议
- 连接,稳定
三次握手
四次挥手
- 客户端、服务端
- 传输完成,释放连接,效率低
- UDP:用户数据报协议
- 不连接、不稳定
- 客户端、服务端:没有明确界限
- 随时可以发送数据
1.6 TCP
- 在开发网络应用程序的时候,我们又会遇到Socket这个概念。Socket是一个抽象概念,一个应用程序通过一个Socket来建立一个远程连接,而Socket内部通过TCP/IP协议把数据传输到网络:
- 使用Socket进行网络编程时,本质上就是两个进程之间的网络通信。其中一个进程必须充当服务器端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它必须主动连接服务器的IP地址和指定端口,如果连接成功,服务器端和客户端就成功地建立了一个TCP连接,双方后续就可以随时发送和接收数据。
- 注意:运行代码时先运行服务端代码,再运行客户端请求连接
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
try {
//1.要知道服务器的地址
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
//2.端口号
int port = 9999;
//3.创建socket连接
Socket socket = new Socket(inetAddress,port);
//4.发送信息流 输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello".getBytes());
outputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 服务端
*/
public class Server {
public static void main(String[] args) {
try {
//1.创建地址
ServerSocket serverSocket = new ServerSocket(9999);
//2.等待客户端连接
Socket socket = serverSocket.accept();
//3.读取客户端的消息
InputStream inputStream = socket.getInputStream();
//管道流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
baos.write(buffer,0,len);
}
System.out.println(baos.toString());
baos.close();
inputStream.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
TCP实现文件上传
/**
* 客户端
*/
public class TCPClient {
public static void main(String[] args) {
try {
//创建一个Socket连接
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9091);
//创建一个输出流
OutputStream outputStream = socket.getOutputStream();
//文件流
FileInputStream file = new FileInputStream(new File("image.jpg"));
//写出文件
byte[] buffer = new byte[1024];
int len;
while((len = file.read(buffer)) != -1) {
outputStream.write(buffer,0,len);
}
outputStream.flush();
//确定服务器接收完毕断开连接
InputStream inputStream = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int line;
while((line = (inputStream.read(buffer))) != -1) {
baos.write(buffer,0,line);
}
baos.flush();
System.out.println(baos.toString());
//关闭资源
file.close();
outputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 服务端
*/
public class TCPServer {
public static void main(String[] args) throws IOException {
//创建服务
ServerSocket serverSocket = new ServerSocket(9091);
//监听客户端连接
//阻塞式监听,会一直等待客户端
Socket socket = serverSocket.accept();
//获取输入流
InputStream inputStream = socket.getInputStream();
//输出文件
FileOutputStream fos = new FileOutputStream(new File("receive.jpg"));
byte[] buffer = new byte[1024];
int len;
while((len = inputStream.read(buffer)) != -1) {
fos.write(buffer,0,len);
}
fos.flush();
//通知客户端我接受完毕了
OutputStream outputStream = socket.getOutputStream();
outputStream.write("接收完毕".getBytes());
//关闭资源
fos.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
1.7 Tomcat
服务端:
- 自定义 Server
- Tomcat Server
客户端:
- 自定义 Client
- 浏览器 Browser
1.8 UDP
类似于发短信,无需知道ip地址,不需要建立连接
/**
* 客户端不需要连接服务端
*/
public class UdpClientDemo01 {
public static void main(String[] args) throws IOException {
//建立一个Socket发送包
DatagramSocket datagramSocket = new DatagramSocket();
String msg = "hello你好";
//接收方的服务器地址
InetAddress inetAddress = InetAddress.getByName("localhost");
int port = 9090;
//建立包
DatagramPacket datagramPacket = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, inetAddress, port);
datagramSocket.send(datagramPacket);
datagramSocket.close();
}
}
/**
* 服务端
* 等待客户端
*/
public class UdpServerDemo01 {
public static void main(String[] args) throws IOException {
//开放端口
DatagramSocket socket = new DatagramSocket(9090);
//接收数据包
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
//阻塞接收
socket.receive(packet);
System.out.println(packet.getAddress().getHostAddress());//127.0.0.1
System.out.println(new String(packet.getData(),0,packet.getLength()));//hello你好
//关闭连接
socket.close();
}
}
UDP聊天实现
/**
* 发送方
*/
public class UdpSender01 {
public static void main(String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket(8880);
//准备数据 控制台输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String data = br.readLine();
byte[] bytes = data.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(bytes,0,bytes.length,new InetSocketAddress("localhost",9999));
//发送包
datagramSocket.send(datagramPacket);
if(data.equals("bye")) {
break;
}
}
datagramSocket.close();
}
}
/**
* 接收方
*/
public class UdpReceiver01 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(9999);
while(true) {
//准备接收包裹
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//阻塞式接收包裹
socket.receive(packet);
//bye断开连接
byte[] data = packet.getData();
//打印接受的包中数据
String receiveData = new String(data,0,packet.getLength());
System.out.println(receiveData);
if (receiveData.equals("bye")) {
break;
}
}
socket.close();
}
}
UDP多线程
实现双方既可以是发送方也可以是接收方
- 发送和接收类:
/**
* 发送线程
*/
public class TalkSender implements Runnable {
DatagramSocket socket = null;
BufferedReader reader = null;
private int fromPort;
private String toIp;
private int toPort;
public TalkSender() {
}
public TalkSender(int fromPort, String toIp, int toPort) {
this.fromPort = fromPort;
this.toIp = toIp;
this.toPort = toPort;
try {
socket = new DatagramSocket(fromPort);
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
while (true) {
String data = reader.readLine();
byte[] bytes = data.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(bytes,0,bytes.length,new InetSocketAddress(this.toIp,this.toPort));
//发送包
socket.send(datagramPacket);
if(data.equals("bye")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
socket.close();
}
}
/**
* 接收线程
*/
public class TalkReceiver implements Runnable {
DatagramSocket socket = null;
private int port;
private String msg;
public TalkReceiver(int port,String msg) {
this.port = port;
this.msg = msg;
try {
socket = new DatagramSocket(port);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
while(true) {
//准备接收包裹
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//阻塞式接收包裹
socket.receive(packet);
//bye断开连接
byte[] data = packet.getData();
//打印接受的包中数据
String receiveData = new String(data,0,packet.getLength());
System.out.println(msg + ":" +receiveData);
if (receiveData.equals("bye")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
socket.close();
}
}
- 启动线程
/**
* 学生端
*/
public class TalkStudent {
public static void main(String[] args) {
//开启两个线程
new Thread(new TalkSender(8087,"localhost",9999)).start();
new Thread(new TalkReceiver(8888,"teacher")).start();
}
}
/**
* 老师端
*/
public class TalkTeacher {
public static void main(String[] args) {
new Thread(new TalkSender(8989,"localhost",8888)).start();
new Thread(new TalkReceiver(9999,"student")).start();
}
}
1.9 URL下载网络资源
例如:https://www.baidu.com/
统一资源定位符:定位资源的,定位互联网上的某一个资源
协议://ip地址:端口/项目名/资源
- url类:
public class UrlDemo {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("http://localhost:8080/helloword/index.jsp?username=zcz&password=1234");
//协议名
System.out.println(url.getProtocol());
//主机ip
System.out.println(url.getHost());
//端口号
System.out.println(url.getPort());
//文件
System.out.println(url.getPath());
//全路径
System.out.println(url.getFile());
//参数
System.out.println(url.getQuery());
}
}
/*
http
localhost
8080
/helloword/index.jsp
/helloword/index.jsp?username=zcz&password=1234
username=zcz&password=1234
*/
- 利用url下载文件
public class UrlDownload {
public static void main(String[] args) throws IOException {
//下载地址
URL url = new URL("http://localhost/temp/demo.txt");
//连接到资源
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream fos = new FileOutputStream("demo.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int len = 0;
while ((len = inputStream.read()) != -1) {
bos.write(len);
}
bos.flush();
//关闭流和连接
bos.close();
fos.close();
inputStream.close();
urlConnection.disconnect();
}
}