Java网络编程
网络通信的要素
-
对方的IP地址
-
对应的端口号
192.168.16,124:5900
TCP/IP参考模型
分为四层,应用层,传输层,网络层,数据链路层(包含链路层和物理层)
得到对应域名的IP地址,可以在cmd中使用ping命令+域名
小结:
-
网络编程上的主要问题
-
准确定位到网络上的一台或者多台主机
-
找到主机之后如何进行数据通信
-
-
网络编程中的要素
-
IP和端口号
-
网络通信协议
-
-
Java中万物皆对象,有这些要素一定有对应的类
IP
IP地址:InetAddress
可以在cmd用ipconfig指令查询相关数据,但是我们能看到的都是局域网IP,只是这个局域网可能比较大(小区),如果公网IP被查到就会遭受入侵
-
唯一定位一台网路上的计算机
-
127.0.0.1是本机IP(localhost),没有网也可以ping通过这个IP
-
IP地址的分类
-
IPV4/IPV6
-
IPV4 127.0.01 ,4个字节组成,每个字节是0-255(2^8),大概有42亿个(2^32),国际不够用,国际分配不均(这些指公网),IPV4私网还够用
-
IPV6 128位,8个无符号整数,十六进制,所以有abcde,这个是用不完的(16^32)
2001:0bb2:aaaa:0015:0000:0000:1aaaa:1312
-
-
公网-私网
-
用到一个网络类InetAddress
package Internet_Stu;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class TestInterAddress {
public static void main(String[] args) {
try {
//查询本机地址的三种方式
InetAddress inet1=InetAddress. getByName("127.0.0.1") ; //127.0.0.1代表本机地址
System.out.println(inet1);
InetAddress inet2=InetAddress. getByName("localhost") ; //localhost代表本地主机
System.out.println(inet2);
InetAddress inet3=InetAddress.getLocalHost();
System.out.println(inet3);
//通过域名查询网站IP地址
InetAddress inet4=InetAddress. getByName("www.baidu.com") ;
System.out.println(inet4);
//inet4已经与百度的IP绑定
System.out.println(inet4.getAddress()); //返回一组地址,这个一般没什么用
System.out.println(inet4.getCanonicalHostName()); //规范名
System.out.println(inet4.getHostAddress()); //主机地址
System.out.println(inet4.getHostName()); //得到对应主机的域名
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
端口
端口表示计算机上的一个程序的进程
-
不同的进程有不同的端口号,用来区分软件
-
被规定0--65535,TCP和UDP协议的端口号不冲突,也就是都有0--65535
-
端口分类
-
公有端口0~1023
-
HTTP:80 输入http://www.baidu.com:80/也可以进百度
-
HTTPS:443
-
FTP:21
-
Telent:23
-
-
程序注册端口:1024~49151,分给用户和程序
-
Tomcat:8080
-
MySQL:3306
-
-
动态,私有端口49152~65535,尽量不要用这里面的端口
//相关控制台命令
netsat -ano //查看所有端口
netsat -ano|findstr "5900" //查看指定端口号
tasklist|findstr "20496"
//linux中,| 表示管道,过滤的意思
-
通信协议
网络通信协议包括:速率,传输码率,代码结构,传输控制
由于问题非常复杂,所以需要分层
TCP/IP协议簇
其中比较重要的两个:
-
TCP:用户传输协议
-
UDP:用户数据报协议
出名的协议
-
TCP
-
IP:网络互联协议(属于网络层)
TCP UDP对比
-
TCP 打电话
-
连接,稳定
-
三次握手,四次挥手
-
分为客户端,服务端(C/S)
-
传输完成,释放连接,效率低
-
-
UDP 发短信
-
不连接,不稳定
-
客户端服务端没有明确界限
-
不管有没有准备好,都可以发给你
-
DDOS:洪水攻击,使用的就是UDP,饱和攻击
-
TCP实现聊天
package com.he.net;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务器端代码
public class TcpServer {
{
try {
//1,开启一个地址,localhost 9999
ServerSocket server = new ServerSocket(9999);
//2,等待客户端链接过来,通过服务器socket的accept方法得到客户端的socket对象
Socket socket=server.accept();
/*3,读取客户端的消息,因为在客户端,
socket这个对象已经通过getOutputStream读取过输入信息了
所以可以直接拿出来*/
InputStream is=socket.getInputStream();
//创建一个管道流
ByteArrayOutputStream baos=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int len;
//所有字节都读进对象里,返回byte数量,如果溢出就返回-1
while((len=is.read(buffer))!=-1){
baos.write(buffer,0,len);//offset就是开始位置和终止位置
}
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.he.net;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
//客户端代码
public class TcpClient {
public static void main(String[] args) {
try {
//1,得到服务器的地址
InetAddress serverIP= InetAddress.getByName("127.0.0.1");
//2,得到端口号
int port=9999;
//3,为该IP,端口号创建一个Socket连接
Socket socket=new Socket(serverIP,port);
//4,发送消息IO流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("第一次网络变成学习".getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
}
//这两段代码都有在finally处理IO流的资源释放问题,同时注意作用域问题,在finally识别不到try语句块中定义的对象
Tips: 创建绑定端口的服务器进程后, 当客户进程的 Socket构造方法返回成功, 表示客户进程的连接请求被加入到服务器进程的请求连接队列中. 虽然客户端成功返回 Socket对象, 但是还没跟服务器进程形成一条通信线路. 必须在服务器进程通过 ServerSocket 的 accept() 方法从请求连接队列中取出连接请求, 并返回一个Socket 对象后, 服务器进程这个Socket 对象才与客户端的 Socket 对象形成一条通信线路.(转自CSDN《Java网络编程精解》)
-
客户端创建了对应服务器IP和端口号的socket,就向服务器发送了一条连接请求
-
服务器端调用ServerSocket的accept()方法,就从请求队列里取出一条连接请求
-
创建ServerSocket的时候可以输入一个请求队列最大长度,如果溢出就弹出错误
-
关于IO流到底用I还是用O
-
首先要声明的是,输入输出都是站在程序所在内存划分的
-
输入流(input)是从其读取数据,输出流是向其写数据(output)
-
从磁盘读数据是输入流,server从client的socket里读数据也是用输入流
-
把内存里的数据写到控制台是输出流,把控制台上键盘输入的数字读到内存中是输入流
-
//服务器代码
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpService {
public static void main(String[] args) {
ByteArrayOutputStream baos=null;
InputStream is=null;
Socket socket=null;
ServerSocket server=null;
try {
//服务器做的任务是接收数据并打印
//1,为服务器进程申请一个端口号
server = new ServerSocket(9999);
//2,从消息队列中取出消息,不能直接取,要通过返回一个Socket对象取数据
socket = server.accept();
//3,从该Socket对象中读取数据,从数据流中取数据,所以是用InputStream对象接收
is = socket.getInputStream();
//使用管道流
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
//从InputStream对象里接收数据
while ((len = is.read(buffer)) != -1)//取长度
{
//数据写进管道类对象里
baos.write(buffer, 0, len);
}
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭资源,提升作用域
if(baos!=null){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(server!=null) {
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
//客户端代码
package TcpByMyself;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class TcpClient {
public static void main(String[] args) {
OutputStream os=null;
Socket socket=null;
try {
//客户端要做的事情是将一个含内容的socket对象发送给服务器端
//1,得到服务器IP地址(总得确定要传送给哪个服务器)
InetAddress inet;
inet = InetAddress.getByName("127.0.0.1");
//2,进一步得到端口号
int port=9999;
//3,创建一个socket对象,这个socket对应着服务器端对应进程的那个socket
socket=new Socket(inet,port);
//4,用IO流对象与socker类对象绑定,socket类有一个getOutputStream()的方法
os=socket.getOutputStream();
//5,往io流对象里写内容,write需要的是Byte[],需要用getByte()将String转换成Byte数组
os.write("第一次学习网络编程".getBytes());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//释放IO流对象的资源
if(os!=null)
{
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null)
{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
这里在finally不写close()部分是不能运行通过的