网络相关概念
IP地址
- 概念:用于唯一标识网络中的每台计算机
- 查看IP地址,控制台 ipconfig
- IP地址表示形式:点分十进制 xx.xx.xx.xx
- 每个十进制数范围:0~255
- IP地址组成 = 网络地址 + 主机地址,比如 192.168.16.69
- IPv6是代替IPv4的下一代IP地址
- IPv4最大的问题是地址资源有限,所有就有了IPv6
- IPv4是4个字节32位 IPv6是16个字节128位
- IPv4地址分类
域名和端口号
域名
- www.baidu.com
- 好处:为了方便记忆,解决IP难记问题
- 概念:将IP地址映射成域名(HTTP协议)
端口号
- 概念:用于标识主机中某个特定的网络程序(例如百度主机中它有很多服务网站服务,邮件服务,Tomcat服务等各种服务),通过端口来监听每一个服务,防止访问发生错乱。
- 表示形式:以整数形式,范围0~65535
- 0~1024已被占用(自己最好不要用),比如 ssh 22 ,ftp 21 ,smtp 25 ,http 80
- 常见的网络程序端口号:tomcat:8080 mysql:3306 oracle:1521 sqlserver:1433
网络通讯协议
TCP/IP (Transmission Control Protocol/Internet Protocol)的简写,中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是lnternet最基本的协议、Internet国际互联网络的基础,简单地说,就是由网络层的IP协议和传输层的TCP协议组成的
TCP协议:传输控制协议
- 使用TCP协议前,须先建立TCP连接,形成传输数据通道
- 传输前,采用"三次握手"方式,是可靠的
- TCP协议进行通信的两个应用进程:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低UDP协议:用户数据协议
UDP协议:用户数据协议
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64K内,不适合传输大量数据
- 因无需连接,故是不可靠的
- 发送数据结束时无需释放资源(因为不是面向连接的),速度快
- 举例:厕所通知:发短信(给对方发消息,不用确定是否对方是否收到)
InetAddress
InetAddress是用于管理IP的类,没有构造器
1. 单例模式
2. 根据静态的方法来返回该对象
public class InetAddress_ {
public static void main(String[] args) throws UnknownHostException {
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
InetAddress byName = InetAddress.getByName("WIN-MBL1NG3RUMG");
System.out.println(byName);
InetAddress byName1 = InetAddress.getByName("www.baidu.com");
System.out.println(byName1);
String address = byName1.getHostAddress();
String name = byName1.getHostName();
System.out.println(name);
System.out.println(address);
}
}
Socket
基本介绍
- 套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准。
- 通信的两端都要有Socket,是两台机器间通信的端点。
- 网络通信其实就是Socket间的通信。
- Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。
- 一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。
TCP网络通讯编程
字节流传输
可靠性
服务端 自己去使用了本地的某个端口 如下代码:端口9999
public class SocketTCPServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端在9999端口监听等待连接...");
Socket socket = serverSocket.accept();
System.out.println("服务端 Socket = " + socket.getClass());
InputStream is = socket.getInputStream();
byte[] buff = new byte[1024];
int readLen = 0;
while ((readLen = is.read(buff)) != -1) {
System.out.println(new String(buff,0,readLen));
}
OutputStream os = socket.getOutputStream();
os.write("hello client".getBytes());
socket.shutdownOutput();
os.close();
is.close();
socket.close();
serverSocket.close();
System.out.println("服务端退出");
}
}
客户端 在去连接服务端的端口时,TCP/IP协议也会随机给客服端一个端口,当在传送比较大的文件时(传输时间长)在Java的Terminal控制台输入netstat -an | more 就可以看到一个和本地端口8888号对应的一个端口号。
public class SocketTCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客服端返回 Socket = "+socket.getClass());
OutputStream os = socket.getOutputStream();
os.write("hello server".getBytes());
socket.shutdownOutput();
InputStream is = socket.getInputStream();
byte[] buff = new byte[1024];
int readLen = 0;
while ((readLen = is.read(buff)) != -1) {
System.out.println(new String(buff,0,readLen));
}
is.close();
os.close();
socket.close();
System.out.println("客服端退出");
}
}
字符流传输
因为socket没有直接提供字符流的传输,如果想用字符流传输,可以通过转换流,将字节流转换成字符流再进行传输
服务端
public class SocketTCPServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String s = null;
while (!(s = br.readLine()).equals("bye")) {
System.out.println(s);
}
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
bw.write("hello client 字符流\nhello client 字符流\nbye");
bw.newLine();
bw.flush();
bw.close();
br.close();
socket.close();
serverSocket.close();
System.out.println("服务端退出");
}
}
客户端
public class SocketTCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
bw.write("hello server 字符流\nhello server 字符流\nbye");
bw.newLine();
bw.flush();
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String s = null;
while (!(s = br.readLine()).equals("bye")) {
System.out.println(s);
}
br.close();
bw.close();
socket.close();
System.out.println("客服端退出");
}
}
问题?
System.out.println(br.readLine());
while ((s = br.readLine())!=null) {
System.out.println(s);
}
原因 首先要明白什么叫流结束,对于读取文件流,读到文件末尾算结束, 但对于socket流,把某次写入到该流的字符读取完能认为该socket流结束吗? 不能,因为这个流还存在,即使流中已经没有数据,但仍然可以继续写出和读入,那么程序自然会继续读流,而流真正的结束就是关闭。 自我理解 待求证 应该是字符串读到最后一行应该不为null或者是不能读取到最后。 好像是关于IO的阻塞和非阻塞 解决办法 在文本的最后加一个字符串作为结束标记
while (!(s = br.readLine()).equals("bye")) {
System.out.println(s);
}
netstat指令
- netstat -an 可以查看当前主机网络情况,包括端口监听情况和网络连接情况
- netstat -an|more 使查看的内容分页 按空格键 显示下一页
- 要求在dos控制台下执行
ctrl+c 停止当前代码运行 - Listening 表示某个端口在监听
- 如果外部程序连接到该端口,就会显示一条连接信息
-
本地地址(IP:端口号) 表示本地这个IP对应的端口号 -
外部地址(IP:端口号) 表示外部连接到本地地址的IP和对应的端口号 -
状态 表示监听的状态 -
用管理员启动的dos控制台输入netstat -anb|more 还可以查看是什么在监听这个端口
UDP网络通讯编程(了解)
基本介绍
- 类 DatagramSocket和 DatagramPacket[数据包|数据报]实现了基于UDP协议网络程序。
- UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
- DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
- UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。
基本流程
案例 发送端 也可以说是接收端
public class UDPSenderB {
public static void main(String[] args) throws IOException {
DatagramSocket dgs = new DatagramSocket(9998);
byte[] bytes = "hello world".getBytes();
DatagramPacket dgp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.159.1"), 9999);
dgs.send(dgp);
byte[] buff = new byte[1024];
dgp = new DatagramPacket(buff, buff.length);
dgs.receive(dgp);
int length = dgp.getLength();
bytes = dgp.getData();
String s = new String(bytes, 0, length);
System.out.println(s);
dgs.close();
System.out.println("B退出");
}
}
接收端 也可以说是发送端
public class UDPReceiverA {
public static void main(String[] args) throws IOException {
DatagramSocket dgs = new DatagramSocket(9999);
byte[] bytes = new byte[1024];
DatagramPacket dgp = new DatagramPacket(bytes, bytes.length);
dgs.receive(dgp);
int length = dgp.getLength();
bytes = dgp.getData();
String s = new String(bytes, 0, length);
System.out.println(s);
bytes = "你好 世界".getBytes();
dgp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.159.1"), 9998);
dgs.send(dgp);
dgs.close();
System.out.println("A退出");
}
}
|