网络编程:可以让设备中的程序与网络上其他设备中的程序进行数据交互(实现网络通信的)
Java提供的网络编程的解决方案在Java.net.*包下
基本的通信架构有2种形式:CS架构(Client客户端/Server服务端)、BS架构(Browser浏览器/Server服务端)
1,需要程序员开发
2,用户需要安装
1,需要程序员开发实现
1,不需要程序员开发实现
2,用户需要安装浏览器
1,需要程序员开发实现
无论是CS架构,还是BS架构的软件都必须依赖网络编程
IP:设备在网络中的地址,是唯一的标志
lP ( lnternet Protocol):全称”互联网协议地址”,是分配给上网设备的唯一标志
IP地址的两种形式:IPv4,IPv6
32位
128位
IPv6分成8段表示,每段每四位编码成一个十六进制位表示,数之间用冒号(:)分开
http://www.*****.com
公网IP:是可以连接互联网的IP地址;内网IP:也叫局域网IP,只能组织机构内部使用
192.168.开头的就是常见的局域网地址,范围即为192.168.0.0--192.168.255.255,专门为组织机构内部使用
127.0.0.1、localhost:代表本机IP,只会寻找当前所在的主机
ipconfig:查看本机IP地址
ping IP地址:检查网络是否连通
代表IP地址
名称 | 说明 |
public static InetAddress getLocalHost() | 获取本机IP,会以一个inetAddress的对象返回 |
public static InetAddress getByName(String host) | 根据ip地址或者域名,返回一个inetAdress对象 |
public String getHostName() | 获取该ip地址对象对应的主机名 |
public String getHostAddress() | 获取该ip地址对象中的ip地址信息 |
public boolean isReachable(int timeout) | 在指定毫秒内,判断主机与该ip对应的主机是否能连通 |
端口:应用程序在设备中唯一的标识
标记正在计算机设备上运行的应用程序的,被规定为一个16位的二进制,范围是0~65535
0~1023,被预先定义的知名应用占用(如:HTTP占用80,FTP占用21)
1024~49151,分配给用户进程或某些应用程序
49152到65535,之所以称为动态端口,是因为它一般不固定分配某种进程,而是动态分配
注意∶我们自己开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则出错
协议:连接和数据在网络中传输的规则
网络上通信的设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议
开放式网络互联标准:OSI网络参考模型
OSI网络参考模型:全球网络互联标准
TCP/IP网络模型:事实上的国际标准
OSI网络参考模型 | TCP/IP网络模型 | 各层应对 | 面向操作 |
应用层 | 应用层 | HTTP、FTP、SMTP... | 应用程序需要关注的:浏览器,邮箱。程序员一般在这一层开发 |
表示层 | |||
会话层 | |||
传输层 | 传输层 | UDP、TCP... | 选择使用的TCP , UDP协议 |
网络层 | 网络层 | IP... | 封装源和目标IP |
数据链路层 | 数据链路层+物理 | 比特流... | 物理设备中传输 |
物理层 |
UDP(User Datagram Protocol):用户数据报协议
通信效率高
特点:无连接、不可靠通信
不事先建立连接,数据按照包发,一包数据包含:自己的IP、程序端口,目的地IP、程序端口和数据(限制在64KB内)等
发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,故是不可靠的
TCP(Transmission Control Protocol):传输控制协议
通信效率相对不高,数据可靠
特点:面向连接、可靠通信
TCP的最终目的:要保证在不可靠的信道上实现可靠的传输
TCP主要有三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接
Java提供了一个java.net.DatagramSocket类来实现UDP通信
DatagramSocket:用于创建客户端、服务端
构造器 | 说明 |
public DatagramSocket() | 创建客户端的Socket对象。系统会随机分配一个端口号 |
public DatagramSocket(int port) | 创建服务端的Socket对象,并指定端口号 |
方法 | 说明 |
public void send(DatagramPacket dp) | 发送数据包 |
public void receive(DatagramPacket p) | 使用数据包接收数据 |
DatagramPacket:创建数据包
构造器 | 说明 |
public DatagramPacket(byte[] buf,int length,InetAddress haddress,int port) | 创建发出去的数据包对象 |
public DatagramPacket(byte[] buf, int length) | 创建用来接收数据的数据包 |
方法 | 说明 |
public int getLength() | 获取数据包,实际接收到的字节个数 |
//客户端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class ddd {
public static void main(String[] args) throws Exception {
DatagramSocket socket=new DatagramSocket();
Scanner sc=new Scanner(System.in);
//多发
while (true) {
System.out.println("请说:");
String msg=sc.nextLine();
//退出
if ("exit".equals(msg)){
System.out.println("欢迎下次光临~~~");
socket.close();//关闭资源
break;
}
byte[]bytes=msg.getBytes();
DatagramPacket packet=new DatagramPacket(bytes,bytes.length,
InetAddress.getLocalHost(),6666);
socket.send(packet);
}
}
}
//服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动~~~~");
DatagramSocket socket=new DatagramSocket(6666);
//创建一个数据包对象
byte[]buffer=new byte[1024*64];
DatagramPacket packet=new DatagramPacket(buffer,buffer.length);
while (true) {
socket.receive(packet);
//接多少,倒多少
int len= packet.getLength();
String rs=new String(buffer,0,len);
System.out.println(rs);
System.out.println("------------------------");
}
}
}
多开操作
Java提供了一个java.net.Socket类来实现TCP通信
客户端程序就是通过java.net包下的Socket类来实现的
构造器 | 说明 |
public Socket(String host , int port) | 根据指定的服务器ip、端口号请求与服务端建立连接,连接通过,就获得了客户端socket |
方法 | 说明 |
public OutputStream getOutputStream() | 获得字节输出流对象 |
public InputStream getInputStream( ) | 获得字节输入流对象 |
2)TCP通信-服务端开发
服务端是通过java.net包下的ServerSocket类来实现的
构造器 | 说明 |
public ServerSocket(int port) | 为服务端程序注册端口 |
方法 | 说明 |
public Socket accept() | 阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象 |
//客户端
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class ccc {
public static void main(String[] args) throws Exception {
Socket socket=new Socket("192.168.187.133",8888);
//创建字节输出流
OutputStream os= socket.getOutputStream();
//字节输出流包装成数据输出流
DataOutputStream dos=new DataOutputStream(os);
Scanner sc=new Scanner(System.in);
while (true) {
System.out.println("请说:");
String msg=sc.nextLine();
if ("exit".equals(msg)){
System.out.println("欢迎下次光临~~~");
dos.close();
socket.close();
break;
}
dos.writeUTF(msg);
dos.flush();
}
}
}
//服务端
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server1 {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动~~~");
ServerSocket serverSocket=new ServerSocket(8888);
//使用ServerSocket对象等待客户端连接请求
Socket socket = serverSocket.accept();
//得到一个字节输入流
InputStream is= socket.getInputStream();
//字节输入流包装成数据输入流
DataInputStream dis=new DataInputStream(is);
while (true) {
try {
//读取客户端的数据
String rs= dis.readUTF();
System.out.println(rs);
} catch (IOException e) {
System.out.println(socket.getRemoteSocketAddress()+"离线了~~~~");
dis.close();
socket.close();
break;
}
}
}
}
因为服务端现在只有一个主线程,只能处理一个客户端的消息,所以不可以支持与多个客户端同时通信
客户端同UDP操作
//服务端
import java.net.ServerSocket;
import java.net.Socket;
public class Server1 {
public static void main(String[] args) throws Exception {
System.out.println("服务端启动~~~");
ServerSocket serverSocket=new ServerSocket(8888);
while (true) {
//使用ServerSocket对象等待客户端连接请求
Socket socket = serverSocket.accept();
System.out.println("有人上线了:"+socket.getRemoteSocketAddress());
//建立独立线程
new ServerReaderThread(socket).start();
}
}
}
//ServerReaderThread
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class ServerReaderThread extends Thread{
public Socket socket;
public ServerReaderThread(Socket socket){
this.socket=socket;
}
@Override
public void run(){
try {
InputStream is= socket.getInputStream();
DataInputStream dis=new DataInputStream(is);
while (true){
try {
String msg= dis.readUTF();
System.out.println(msg);
} catch (IOException e) {
System.out.println("有人下线了:"+socket.getRemoteSocketAddress());
dis.close();
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
BS架构的基本原理:
http://服务器IP:服务器端口
注意:服务器必须给浏览器响应HTTP协议规定的数据格式,否则浏览器不识别返回的数据
HTTP协议规定:响应给浏览器的数据格式必须满足如下格式
//ServerReaderRunnable
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
public class ServerReaderRunnable implements Runnable{
private Socket socket;
public ServerReaderRunnable(Socket socket){
this.socket=socket;
}
@Override
public void run(){
try {
OutputStream os= socket.getOutputStream();
PrintStream ps=new PrintStream(os);
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println();//换行
ps.println("猜猜我是谁?");
ps.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//服务端
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Server {
public static void main(String[] args) throws Exception{
System.out.println("服务端启动~~~");
ServerSocket serverSocket=new ServerSocket(8888);
ThreadPoolExecutor pool = new ThreadPoolExecutor(16 * 2, 16 * 2, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(8), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
while (true) {
//使用ServerSocket对象等待客户端连接请求
Socket socket = serverSocket.accept();
pool.execute(new ServerReaderRunnable(socket));
}
}
}