基础知识
网络通信
概念:两台或多台设备进行数据的传输。
网络
概念:两台或多台设备通过一定物理设备连接来构成网络。
网络的分类:
- 局域网:(范围逐渐变大),一个小型区域
- 城域网:一个城市
- 广域网:一个国家(典型代表是局域网)
网络编程的目的
网络编程的目的:直接或间接地通过网络协议与其他计算机实现数据交换进行通讯
要想实现网络编程,需要关注两个问题:
1.如何准确定位网络上的一台或多台主机,定位主机上的特定应用
2.找到主机以后怎么进行可靠高效的数据传输
IP地址
- 概念:唯一标识主机的。
- 查看ip地址:ipconfig
- IP地址表示:4个字节(32位)表示,一个字节的范围是0~255;
- IP地址的格式:网络地址+主机地址。
- IPV6地址(解决了IPV4在网络地址上的资源有限问题),IPV6可以实现多种接入设备连入互联网。 IPV6是由128位(128/16 = 8字节)表示一个地址。
域名
- www.baidu.com着就是百度的域名,他可以理解成是IP地址的映射(因为ip地址不容易记忆,所以就有域名的出现)
端口
概念:用于标识计算机上某个特定的网路程序。
端口号:范围0~65535.
电脑浏览器如果想访问一个网站需要通过(IP+端口号)
在网络开发中最好不要使用0~1024号端口,因为这些端口可能已经被其他服务器使用了
- 一个服务要接收和发送数据的话,需要有一个端口。端口就类似于人的耳朵,我们要听懂别人的话,必须要有耳朵
网络通信协议
TCP协议于UDP协议的区别
- TCP类似于打电话
- UDP类似于发短信
TCP 协议:传输控制协议
就是确定是否连接成功,需要进行三次确认。
- TCP协议的优点:需要进行三次握手(是可靠的)
- 缺点就是效率低。
UDP协议:用户数据协议
- UDP协议无法保证传输的数据一定被接收到
- UDP协议就是没有确认对方是否能够接收到消息,就直接传输信息
- 比如说:你发送信息给别人,但是这个电话号码可能停机了或者说注销了,你不能确保别人能接收消息,类似于UDP协议
假如说现在有一个人也想要打电话给kim,由于kim这个时候在和tom打电话,他们两个如果电话没有挂掉,这个人的电话是打不通的,就类似于TCP协议要释放已经建立的连接
tom发信息给kim,另外一个人同样也可以发信息给kim,就类似于UDP协议不需要释放资源
简单的API使用
InetAddress
一个InetAddress类的对象就当于是一个IP地址
相关方法
getByName(String host) 、 getLocalHost()
两个常用方法:getHostName() 获取域名 / getHostAddress() 获取主机地址
实例
代码
package 网络编程;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class API {
public static void main(String[] args) throws UnknownHostException {
//获取本机的IntetAddress的对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
//根据指定主机名,获取InetAddress对象
InetAddress host1 = InetAddress.getByName("LAPTOP-612T08NP");
System.out.println(host1);
//根据域名返回InetAddress对象,比如百度的域名
InetAddress host2 = InetAddress.getByName("www.baidu.com");
System.out.println(host2);
//根据域名获取Ip
String hostAddress = host2.getHostAddress();
System.out.println("host2 对应的IP = "+ hostAddress);
}
}
常用的方法就是上面四种,分别来获取IP和对应的域名。
Socket理解
- Socket就类似于通信的通道,发送数据是通过socket
- TCP编程:可靠的,但是效率低
- UDP编程:不可靠的,但是效率高
简单理解就是数据两端的插头,让客户端与服务器端可以很好的取得连接。目的就是为了通信,而通信的目的就是用来发送数据和接收数据。
TCP网络通信案例
案例一:使用字节流。编写一个服务器端和一个客户端,服务器端在9999端口进行监听,客户端连接到服务器端发送一个“hello world”然后退出,服务器端接收到客户端的信息输出并退出。
服务端:
package 网络编程;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCPServer {
public static void main(String[] args) throws IOException {
//在本机9999端口接听,等待连接
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器,在9999端口监听,等待连接。。。");
//当没有客户端连接999端口时,程序会阻塞,等待连接
//如果有客户端连接。则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("socket = "+socket.getClass());
}
}
此时9999端口已经占用了,如果再次点击运行,程序会报错。
案例1:TCP编写(字节读写)
案例要求:
客户端:
- 连接服务端(IP,端口)
- 连接上后,生成Socket,通过socket.getOutputStream()函数创建输出流
- 通过输出流,写入数据到数据通道(服务器端来接收)
package 网络编程;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketTCPClient {
public static void main(String[] args) throws IOException {
//连接TCP端(ip,端口)
//连接本机9999端口,如果连接成功,返回socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
System.out.println("客户端 socked返回"+socket.getClass());
//连接成功后,生成socket对象,通过socket.getOutputStream()(输出流)输出hello server
//得到和socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//通过输出流,写入数据到数据通道
outputStream.write("hello server".getBytes());
//关闭流对象的socket,
outputStream.close();
socket.close();
System.out.println("客户端退出!");
}
}
服务端
- 在本机的9999 端口监听,等待连接
- 当没有客户端连接9999 端口时,程序会阻塞,等待连接
- 通过socket.getInputStream();函数来读取客户端写入到数据通道的数据,然后显示出来。
package 网络编程;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCPServer {
public static void main(String[] args) throws IOException {
//在本机9999端口接听,等待连接
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器,在9999端口监听,等待连接。。。");
//当没有客户端连接999端口时,程序会阻塞,等待连接
//如果有客户端连接。则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("服务器 socket = "+socket.getClass());
//通过输入流来读取客户端传来的数据
InputStream inputStream = socket.getInputStream();
//IO读取
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLen));//根据
}
//关闭流
inputStream.close();
socket.close();
serverSocket.close();
}
}
注意事项
- 运行程序的时候一定是先运行server段,再运行client客户端
案例2
服务端
package 网络编程;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCPServer {
public static void main(String[] args) throws IOException {
//在本机9999端口接听,等待连接
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器,在9999端口监听,等待连接。。。");
//当没有客户端连接999端口时,程序会阻塞,等待连接
//如果有客户端连接。则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("服务器 socket = "+socket.getClass());
//通过输入流来读取客户端传来的数据
InputStream inputStream = socket.getInputStream();
//IO读取
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLen));//根据
}
//获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
//写入数据到数据通道
outputStream.write("hello,client".getBytes());
//关闭流
inputStream.close();
socket.close();
serverSocket.close();
//关闭输出流
outputStream.close();
}
}
- server端有输出,但是没有退出,好像是卡到了什么地方。clint并没有接收到server端发送的数据。
- 如何解决上面的问题,就是给两个端设置结束标志。socket。shutdownOutput();关闭了输出的结束。
代码优化
服务端:
package 网络编程;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCPServer {
public static void main(String[] args) throws IOException {
//在本机9999端口接听,等待连接
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器,在9999端口监听,等待连接。。。");
//当没有客户端连接999端口时,程序会阻塞,等待连接
//如果有客户端连接。则会返回Socket对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("服务器 socket = "+socket.getClass());
//通过输入流来读取客户端传来的数据
InputStream inputStream = socket.getInputStream();
//IO读取
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLen));//根据
}
//获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
//写入数据到数据通道
outputStream.write("hello,client".getBytes());
//设置结束标志
socket.shutdownOutput();
//关闭流
inputStream.close();
socket.close();
serverSocket.close();
//关闭输出流
outputStream.close();
}
}
客户端:
package 网络编程;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketTCPClient {
public static void main(String[] args) throws IOException {
//连接TCP端(ip,端口)
//连接本机9999端口,如果连接成功,返回socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
System.out.println("客户端 socked返回"+socket.getClass());
//连接成功后,生成socket对象,通过socket.getOutputStream()(输出流)输出hello server
//得到和socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
//通过输出流,写入数据到数据通道
outputStream.write("hello server".getBytes());
//设置结束标志
socket.shutdownOutput();
//获取和socket关联的输入流,读取数据(字节),并显示
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLen));//根据
}
//关闭流对象的socket,
outputStream.close();
socket.close();
System.out.println("客户端退出!");
//关闭输入流
inputStream.close();
}
}