网络编程
1.1、概述
网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。中间最主要的就是数据包的组装,数据包的过滤,数据包的捕获,数据包的分析,当然最后再做一些处理,代码、开发工具、数据库、服务器架设和网页设计。
计算机网络
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
网络编程的目的
网络编程:TCP/IP
实现无线电台…传播交流信息,数据交换,通信等。
想要达到以上效果需要什么?
- 如何准确地定位网络上的一台主机,如 IP 地址:192.168.13.16; 端口,定位到该计算机上的某个资源
- 找到了主机如何传输数据?
1.2、网络通信的要素
如何实现网络通信?
通信双方的地址:
- IP地址
- 端口号
- 192.168.16,124:5900
规则:网络通信的协议
TCP/IP参考模型:
注:
1.网络编程中的两个主要问题
- 如何准确的定位到网络上的一台或多台主机
- 找到主机之后进行通信
2.网络编程中的要素
- IP和端口号
- 网络通信协议
1.3、IP
IP地址: InetAddress(操作类)
- 唯一定位一台网络上的计算机
- 127.0.0.1;本机localhost
IP地址的分类
- ipv4/ipv6
- IPV4 127.0.0.1,四个字节组成
- IPV6 fc90::5cde:b87a:66a0:299c%5 ,128位
- 公网(互联网) / 私网(局域网)
- ABCD类地址
- A类网络的IP地址范围为:1.0.0.1-126.255.255.254;
- B类网络的IP地址范围为:128.1.0.1-191.255.255.254;
- C类网络的IP地址范围为:192.0.1.1-223.255.255.254
- ABCD类地址
import java.net.InetAddress;
import java.net.UnknownHostException;
//测试IP
public class TestInetAddress {
public static void main(String[] args) {
try {
//查询本机地址
InetAddress inetAddress=InetAddress.getByName("127.0.0.1");
System.out.println(inetAddress);
//查询网站IP地址
InetAddress inetAddress2=InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress2);
System.out.println("=======================");
System.out.println(inetAddress2.getAddress());
System.out.println(inetAddress2.getCanonicalHostName());
System.out.println(inetAddress2.getHostAddress());
System.out.println(inetAddress2.getHostName());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
1.4、端口
端口表示计算机上的一个程序的进程
-
不同的进程有不同的端口号,用来区分软件。
-
单个协议下端口号不能冲突
- 公有端口 0-1023
- 默认端口号
- Http:80
- Https:443
- FTP:21
-
程序注册端口:1024-49151,分配用户或程序
- Tomcat:8080
- MySQL:3306
- Oracle:1521
-
动态、私有:49152-65535
查看端口号
netstat -ano #查看所有端口
netstat -ano|findstr "3972" #查看指定端口
tasklist|findstr "9540" #查看指定端口的进程
import java.net.InetSocketAddress;
public class TestInetSocketAddress {
public static void main(String[] args) {
InetSocketAddress SocketAddress=new InetSocketAddress("127.0.0.1",8080);
InetSocketAddress SocketAddress2=new InetSocketAddress("localhost",8080);
System.out.println(SocketAddress);
System.out.println(SocketAddress2);
System.out.println("=======================");
System.out.println(SocketAddress.getAddress());
System.out.println(SocketAddress.getHostName());//地址
System.out.println(SocketAddress.getPort());//端口
System.out.println(SocketAddress.getClass());
}
}
1.5、通信协议
协议:一种约定
网络通信协议:是一种网络通用语言,为连接不同操作系统和不同硬件体系结构的互联网络引提供通信支持,是一种网络通用语言。
TCP/IP分层协议
- 网络接口层协议:Ethernet 802.3、Token Ring 802.5、X.25、Frame relay、HDLC、PPP ATM等。
- 网络层协议:IP(Internet Protocol,英特网协议)、ICMP(Internet Control Message Protocol,控制报文协议)、ARP(Address Resolution Protocol,地址转换协议)、RARP(Reverse ARP,反向地址转换协议)。
- 传输层协议: TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram protocol,用户数据报协议)。
- 应用层协议:FTP(File Transfer Protocol,文件传输协议)、TELNET(用户远程登录服务协议)、DNS(Domain Name Service,是域名解析服务)、SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)、NFS(Network File System,网络文件系统)、HTTP(Hypertext Transfer Protocol,超文本传输协议)。
TCP:打电话
- 连接、稳定
- 三次握手(最少需要三次,保证稳定连接)、四次挥手
- 客户端、服务端
- 传输完成、释放连接,效率低
UDP:发短信
- 不连接、不稳定
- 客户端、服务端,没有明确的界限
- 不管有没有准备好,都可以发送
1.6、TCP
TCP实现聊天
客户端
1.连接服务器Socket
2.发送消息
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
//客户端
public class TcpClientDemon {
public static void main(String[] args) {
Socket socket=null;
OutputStream os=null;
try {
//1.要知道服务器地址、端口号
InetAddress serverIp=InetAddress.getByName("127.0.01");
int port=9999;
//2.创建一个socket连接
socket=new Socket(serverIp,port);
//3.发送信息,io流
os=socket.getOutputStream();
os.write("你好!".getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(socket!=null){
socket.close();
}
if(os!=null){
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
服务器
1.建立服务端口ServerSocket
2.等待用户连接 accept
3.接受用户的消息
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务器端
public class TcpServerDemon {
public static void main(String[] args) {
ServerSocket serverSocket=null;
Socket socket=null;
InputStream is=null;
ByteArrayOutputStream baos=null;
try {
//1.得有一个地址
serverSocket=new ServerSocket(9999);
//2.等待客户端连接
socket=serverSocket.accept();
//3.读取客户端的消息
is=socket.getInputStream();
//4.管道流
baos = new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int len;
while ((len=is.read(buffer))!=-1){
baos.write(buffer,0,len);
}
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
//关闭资源
if(baos!=null){
baos.close();
}
if(is!=null){
is.close();
}
if(socket!=null){
socket.close();
}
if(serverSocket!=null){
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
TCP实现文件上传
服务器
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServerDemon02 {
public static void main(String[] args) throws IOException {
//1.创建服务
ServerSocket serverSocket = new ServerSocket(9002);
//2.等待客户端连接
Socket socket=serverSocket.accept();
//3.获取输入流
InputStream is = socket.getInputStream();
//4.文件输出
FileOutputStream fos = new FileOutputStream(new File("receive.png"));
byte [] buffer=new byte[1024];
int len;
while ((len=is.read())!=-1){
fos.write(buffer,0,len);
}
//5.通知客户端接收完毕
OutputStream os=socket.getOutputStream();
os.write("接收完毕!可以断开连接".getBytes());
//6.关闭资源
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
客户端
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class TcpClientDemon02 {
public static void main(String[] args) throws IOException {
//1.创建一个socket连接
Socket socket=new Socket(InetAddress.getByName("127.0.0.1"),9002);
//2.创建一个输出流
OutputStream os=socket.getOutputStream();
//3.文件流
FileInputStream fis=new FileInputStream(new File("background.png"));
//4.写出文件
byte [] buffer=new byte[1024];
int len;
while ((len=fis.read(buffer))!=-1){
os.write(buffer,0,len);
}
//通知服务器已经传输完毕
socket.shutdownOutput();
//5.确定服务器接收完毕后,断开连接
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte [] buffer2=new byte[1024];
int len2;
while ((len2=is.read(buffer2))!=-1){
baos.write(buffer2,0,len2);
}
System.out.println(baos.toString());
//6.关闭资源
baos.close();
is.close();
fis.close();
os.close();
socket.close();
}
}
1.7、UDP
UDP实现发送消息
发送端
import java.io.IOException;
import java.net.*;
//不需要连接服务器
public class UdpClientDemon01 {
public static void main(String[] args) throws IOException {
//1.建立一个Socket
DatagramSocket socket = new DatagramSocket();
//发送的内容
String msg="你好,服务器!";
//发送给谁
InetAddress localhost=InetAddress.getByName("localhost");
int port=9099;
//2.建包,数据,数据长度起始,发送给谁
DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,port);
//3.发送包
socket.send(packet);
//关闭资源
socket.close();
}
}
接收端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//需要等待客户端连接
public class UdpServerDemon01 {
public static void main(String[] args) throws IOException {
//开放端口
DatagramSocket socket=new DatagramSocket(9099);
//接收数据
byte []buffer=new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
System.out.println(packet.getAddress().getHostAddress());
System.out.println(new String(packet.getData(),0,packet.getLength()));
//关闭资源
socket.close();
}
}
循环发送消息
发送端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;
public class UdpSenderDemon01 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(8888);
//准备数据,从控制台读取
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
String data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));
socket.send(packet);
if(data.equals("bye")){
break;
}
}
socket.close();
}
}
接收端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpReceiveDemon01 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(6666);
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, data.length);
System.out.println(receiveData);
if(receiveData.equals("bye")){
break;
}
}
socket.close();
}
}
多线程实现聊天
发送端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class TalkSend implements Runnable{
DatagramSocket socket=null;
BufferedReader reader=null;
private int fromPort;
private String toIP;
private int toPort;
public TalkSend() {
}
public TalkSend(int fromPort, String toIP, int toPort) throws SocketException {
this.fromPort = fromPort;
this.toIP = toIP;
this.toPort = toPort;
socket = new DatagramSocket(fromPort);
reader=new BufferedReader(new InputStreamReader(System.in));
}
public void run() {
while (true){
String data = null;
try {
data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress(this.toIP,this.toPort));
socket.send(packet);
if(data.equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
接收端
package com.chat;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class TalkReceive implements Runnable {
DatagramSocket socket=null;
private int port;
private String msgFrom;
public TalkReceive(int port,String msgFrom) {
this.port = port;
this.msgFrom=msgFrom;
try {
socket = new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
}
public void run() {
while (true){
//准备接收包
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
try {
socket.receive(packet);//阻塞式接收包
//断开连接,bye
byte[] data = packet.getData();
String receiveData= new String(data, 0, data.length);
System.out.println(msgFrom+":"+receiveData);
if(receiveData.equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
开启线程
import java.net.SocketException;
public class TalkStudent {
public static void main(String[] args) throws SocketException {
//开启两个线程
new Thread(new TalkSend(7777,"localhost",9999)).start();
new Thread(new TalkReceive(8888,"老师")).start();
}
}
import java.net.SocketException;
public class TalkTeacher {
public static void main(String[] args) throws SocketException {
new Thread(new TalkSend(5555,"localhost",8888)).start();
new Thread(new TalkReceive(9999,"学生")).start();
}
}
1.8、URL
URL由三部分组成:资源类型、存放资源的主机域名、资源文件名。
也可认为由4部分组成:协议、主机、端口、路径
protocol(协议)
指定使用的传输协议,下表列出 protocol 属性的有效方案名称。 最常用的是HTTP协议,它也是WWW中应用最广的协议。
file 资源是本地计算机上的文件。格式file:///,注意后边应是三个斜杠。
ftp 通过 FTP访问资源。格式 FTP://
gopher 通过 Gopher 协议访问该资源。
http 通过 HTTP 访问该资源。 格式 HTTP://
https 通过安全的 HTTPS 访问该资源。 格式 HTTPS://
mailto 资源为电子邮件地址,通过 SMTP 访问。 格式 mailto:
MMS 通过 支持MMS(流媒体)协议的播放该资源。(代表软件:Windows Media Player)格式 MMS://
ed2k 通过 支持ed2k(专用下载链接)协议的P2P软件访问该资源。(代表软件:电驴) 格式 ed2k://
Flashget 通过 支持Flashget:(专用下载链接)协议的P2P软件访问该资源。(代表软件:快车) 格式 Flashget://
thunder 通过 支持thunder(专用下载链接)协议的P2P软件访问该资源。(代表软件:迅雷) 格式 thunder://
news 通过 NNTP 访问该资源。
hostname(主机名)
是指存放资源的服务器的域名系统(DNS) 主机名或 IP 地址。有时,在主机名前也可以包含连接到服务器所需的用户名和密码(格式:username:password@hostname)。
port(端口号)
整数,可选,省略时使用方案的默认端口,各种传输协议都有默认的端口号,如http的默认端口为80。如果输入时省略,则使用默认端口号。有时候出于安全或其他考虑,可以在服务器上对端口进行重定义,即采用非标准端口号,此时,URL中就不能省略端口号这一项。
path(路径)
由零或多个“/”符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。
parameters(参数)
这是用于指定特殊参数的可选项。
query(查询)
可选,用于给动态网页(如使用CGI、ISAPI、PHP/JSP/ASP/ASP.NET等技术制作的网页)传递参数,可有多个参数,用“&”符号隔开,每个参数的名和值用“=”符号隔开。