目录放在这里太长了,附目录链接大家可以自由选择查看--------Java学习目录
网络编程
,就是在一定的协议下,实现两台计算机的通信的程序.虚拟终端协议(TELNET),文件传输协议(FTP,File Transfer Protocol),电子邮件传输协议(SMTP,Simple Mail Transfer Protocol),域名服务(DNS,Domain Name Service),网上新闻传输协议(NNTP,NET News Transfer Protocol)和超文本传送协议(HTTP,HyperText Transfer Protocol)
等端到端的协议:传输控制协议(TCP,Transmission Control Protocol)和用户数据报协议(UDP,User Datagram Protocol)
。TCP是面向连接的
协议,它提供可靠的报文传输和对上层应用的连接服务。为此,除了基本的数据传输外,它还有可靠性保证,流量控制,多路复用,优先权和安全性控制等功能。UDP是面向无连接
的不可靠传输协议,主要用于不需要TCP的排序和流量控制等功能的应用程序。java.net
包中包含的类和接口,它们提供低层次的通信细节。我们可以直接使用这些类和接口,来专注于网络程序开发,而不用考虑通信的细节。java.net
包中提供了两种常见的网络协议的支持:无连接
通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在
,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据
。由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议
都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性
,因此在传输重要数据时不建议使用UDP协议
。UDP的交换过程如下图所示。可靠无差错
的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手"",每次断开连接都要"四次挥手".”
TCP的半关闭造成的
.因为TCP连接是全双工的(即数据可以在两个方向上同时传递),所以进行关闭时每个方向上都要单独进行关闭.这个单方向的关闭就叫做半关闭.当一方完成它的数据发送任务,就发送一个FIN来向另一方通告将要终止这个方向的连接.协议
+IP地址
+端口号
三元组合,就可以标识网络中的进程了,那么进程间的通信就可以利用这个标识与其它进程进行交互。a.b.c.d
的形式,例如192.168.65.100
。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个.ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
,号称可以为全世界的每一粒沙子编上一个网址,这样就解决了网络地址资源数量不够的问题127.0.0.1
、localhost
。客户端(Client)与服务端(Server
)。java.net.Socket
类表示。创建Socket
对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。java.net.ServerSocket
类表示。创建ServerSocket
对象,相当于开启一个服务,并等待客户端的连接。Socket
类:该类实现客户端套接字,是计算机之间通信的一种约定或一种方式,通过Socket这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据.public Socket(String host, int port)
:创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的host是null ,则相当于指定地址为回送地址。public InputStream getInputStream()
: 返回此套接字的输入流。public OutputStream getOutputStream()
: 返回此套接字的输出流。public void close()
:关闭此套接字。public void shutdownOutput()
: 禁用此套接字的输出流。ServerSocket
类:这个类实现了服务器套接字,该对象等待通过网络的请求。public ServerSocket(int port)
:使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上,参数port就是端口号。public Socket accept()
:侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。/**
* 客户端
* 向服务器端发送请求,接收服务器端返回请求,读取返回数据
*/
public class TCPClient {
public static void main(String[] args) throws IOException {
//1. 创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口号
Socket socket = new Socket("127.0.0.1", 6666);
//2. 使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
//3. 使用网络字节输出流OutputStream对象中的方法write,给服务器发送数据
//write方法只能传入int或者字节数组,传入字符串的话要进行转换
os.write("客户端向服务器发送第一次信息".getBytes());
//下面是用来接收服务器返回的数据
//4. 使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
InputStream is = socket.getInputStream();
//5. 使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据
byte[] mes = new byte[1024];
int len = is.read(mes);
System.out.println(new String(mes,0,len));
//6. 释放资源
socket.close();
}
}
服务器端
/**
* 服务器端
* 接收客户端请求,读取客户端发送的数据,给客户端写回数据
*/
public class TCPServer {
public static void main(String[] args) throws IOException {
//1. 创建服务器ServerSocket对象并且指定监听端口号
ServerSocket serverSocket = new ServerSocket(6666);
//2. 使用ServerSocket对象中的方法accpet(),获取到请求的客户端对象Socket
Socket socket = serverSocket.accept();
//3. 使用Socket对象中的方法getInputStream()获取字节输入流InputStream对象
InputStream is = socket.getInputStream();
//4. 使用字节输入流InputStream对象中的方法read,读取客户端发送的数据
byte[] mes = new byte[1024];
int len = is.read(mes);
System.out.println(new String(mes,0,len));
//下面是服务器端向客户端返回数据
//5. 使用Socket对象中的方法getOutputStream获取字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
//6. 使用字节输出流OutputStream对象中的方法write,给客户端写数据
os.write("服务器端收到客户端数据".getBytes());
//7. 关闭资源
serverSocket.close();
}
}
public static void main(String[] args) throws IOException {
String data = "UDP发送方发送数据";
//1. 实例化套接字,并指定发送方端口
DatagramSocket datagramSocket = new DatagramSocket(8888);
//2. 指定数据目的地的地址,以及目标端口
InetAddress destination = InetAddress.getByName("localhost");
//3. 创建数据包,指定目标端口
DatagramPacket datagramPacket =
new DatagramPacket(data.getBytes(), data.getBytes().length, destination, 9999);
//4. 发送数据
datagramSocket.send(datagramPacket);
//5. 释放资源
datagramSocket.close();
}
接收方
public static void main(String[] args) throws IOException {
//1. 实例化套接字,并指定接收端口
DatagramSocket datagramSocket = new DatagramSocket(9999);
byte[] buf = new byte[1024];
//2. 定义接收数据的数据包
DatagramPacket datagramPacket = new DatagramPacket(buf, 0, buf.length);
//3. 调用接收方法
datagramSocket.receive(datagramPacket);
String data = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
System.out.println(data);
// 4. 释放资源
datagramSocket.close();
}
public static void main(String[] args) throws UnknownHostException {
//1. 通过getLocalHost()获得InetAddress对象
InetAddress ia1 = InetAddress.getLocalHost();
System.out.println("主机IP地址:"+ia1.getHostAddress());
System.out.println("主机名:"+ia1.getHostName());
//2. 通过getByName(域名)
InetAddress ia3 = InetAddress.getByName("www.baidu.com");
System.out.println("主机IP地址:"+ia3.getHostAddress());
System.out.println("主机名:"+ia3.getHostName());
//3. 根据getByName(IP地址)获取InetAddress对象
InetAddress ia2 = InetAddress.getByName("localhost");
System.out.println("主机IP地址:"+ia2.getHostAddress());
System.out.println("主机名:"+ia2.getHostName());
}
public static void main(String[] args) throws UnknownHostException {
// 创建对象方式1
InetSocketAddress isa1 = new InetSocketAddress("localhost", 8888);
// 创建对象方式2
InetAddress localHost = InetAddress.getLocalHost();
InetSocketAddress isa2 = new InetSocketAddress(localHost, 9999);
System.out.println("主机名称:"+isa1.getHostName());
System.out.println("端口号:"+isa1.getPort());
}
协议,存放资源的主机域名,端口号和资源文件名
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("https://www.baidu.com:80/index.html");
System.out.println("协议名称:"+url.getProtocol());
System.out.println("域名:"+url.getHost());
System.out.println("端口号:"+url.getPort());
System.out.println("路径"+url.getPath());
}
本地字节输入流
,从硬盘读取文件数据到程序中。网络字节输出流(Socket提供)
,写出文件数据到服务端。网络字节输入流(Socket提供)
,读取文件数据到服务端程序。本地字节输出流
,写出文件数据到服务器硬盘中。网络字节输出流(Socket提供)
, 向客户端返回"上传成功"信息网络字节输入流(Socket提供)
, 读取服务器返回数据/**
* 文件上传客户端
*/
public class UploadClient {
public static void main(String[] args) throws IOException {
//1. 创建本地文件输入流FileInputStream对象,绑定要上传的文件数据
FileInputStream fis = new FileInputStream(new File("d:\\test.txt"));
//2. 创建客户端对象,构造时绑定服务器IP地址和端口号
Socket socket = new Socket("localhost", 9999);
//3. 使用Socket中的getOutputStream,获取网络字节输出流OutputStream
OutputStream os = socket.getOutputStream();
//4. 使用本地文件输入流FileInputStream对象中read方法,读取文件内容
byte[] message = new byte[1024];
int len = 0;
while((len=fis.read(message))!=-1){
//5. 使用网络字节输出流OutputStream对象中write方法,将读取到内容上传到服务器
os.write(message,0,len);
}
//6. 使用Socket中的getInputStream,获取网络字节输出流InputStream
InputStream is = socket.getInputStream();
while((len=is.read(message))!=-1){
//7. 使用网络字节输入流InputStream对象中方法,获取服务器端返回的数据
System.out.println(new String(message,0,len));
}
//8. 释放资源(FileInputStream,Socket)
fis.close();
socket.close();
}
}
/**
* 文件上传服务器端
*/
public class UploadServer {
public static void main(String[] args) throws IOException {
//1. 创建服务器端ServerSocket对象,指定监听端口号
ServerSocket serverSocket = new ServerSocket(9999);
//2. 调用accept方法获得Socket对象,监听客户端信息
Socket socket = serverSocket.accept();
//3. 使用socket对象中的getInputStream,获得网络字节输入流对象
InputStream is = socket.getInputStream();
//4. 将获取到的数据保存到指定文件夹,因此要先判断文件夹是否存在
File file = new File("d:\\upload");
if (!file.exists()){
file.mkdir();
}
//5. 创建本地文件输出流对象FileOutputStream,构造时指定输出目的地
FileOutputStream fos = new FileOutputStream(new File("d:\\upload\\test.txt"));
//6. 使用网络字节输入流对象方法read,读取客户端传递数据
int len=0;
byte[] message = new byte[1024];
while((len=is.read(message))!=-1){
//7. 使用本次字节输出流对象FileOutputStream的write方法,保存文件
fos.write(message,0,len);
}
//8. 使用socket的方法得到OutputStream对象
OutputStream os = socket.getOutputStream();
//9. 使用网络字节输出流OutputStream对象向客户端返回数据
os.write(new String("上传成功").getBytes());
//10. 释放资源
fos.close();
socket.close();
}
}
从此输入流中读取数据,如果没有输入可用,则此方法将阻塞
.在Client中第一个read方法是读取本地文件然后通过网络字节输出流发送到服务器中,但是发送完之后,传递给服务器的文件是没有结束标记的,于是在Server中的read方法中,无法满足while循环的跳出条件因此就在此处阻塞了,Server后面的方法也就无法继续执行了,这造成了server的阻塞,与此同时,Client中第二个read方法需要读取服务端传递的网络字节输入流,但是由于Server的阻塞,导致没有向客户端反馈数据,因此Client端也阻塞了 /**
* 优化1:文件名写死问题解决
* 文件命名规则:时间毫秒数+文件名后缀
* 防止同名文件被覆盖
*/
String filename=System.currentTimeMillis()+".txt";
//5. 创建本地文件输出流对象FileOutputStream,构造时指定输出目的地
FileOutputStream fos = new FileOutputStream(new File(file+"\\"+filename));