网络通信
一 概述
1.网络模型
OSI(Open System Interconnection,开放式系统互联)模型,是对网络系统结构的概括,将网络分为七层:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
2.IP协议
网络层协议,规定了在互联网上确定与寻找计算机的规则。
3.TCP协议
传输层的一种数据传输协议,数据传输前通过“三次握手”建立连接,然后再发送数据,适用于对数据准确性要求较高的情况,由于数据传输前需要建立连接,传输速度较慢。
在建立连接的三次握手中,客户端通过第一次握手向服务端发送建立连接的请求,如果服务端同意请求,将反馈信息发送给客户端,貌似这样已经建立了连接,其实不然。第三次握手正是为了甄别与剔除延迟无效的请求。假如有一个请求从客户端发出以后,由于各种原因延迟达到服务器端,而此时客户端已放弃了该请求,建立了新的请求。如果服务器端接收该请求以后,不做甄别,就会一直等待客户端发来的数据,造成服务器端资源浪费。
- SYN:标志位,用于标识信息的性质,SYN=1表示该信息是用来建立连结的。
- ACK:acknowledgement,标识位,用于表示该信息是否是对方确认的结果,取值为0,表示确认字段无效;为1,表示确认字段有效。
- seq:sequence number,发送号,用于表示确认结果,如果接受的ack值比发送的seq值大1,表示同意建立连接。
- ack:acknowledge number,确认号,用来表示确认结果,如果同意建立连接,则ack=seq+1。
4.UDP协议
传输层的一种数据传输协议,数据传输前不需要建立连接,适用于对数据准确性要求不高的情况,传输数据较快,一般聊天信息都通过该协议传输。
5.HTTP协议
HTTP协议属于应用层协议,为操作系统或网络应用程序提供访问网络服务的接口。
6.端口port
当数据到达计算机后,为了找到目标应用程序,为每一个应用程序分配了一个整数值,取值0-65535,这个整数值就是端口,从中可以看出,端口代表了计算机上一个应用程序,保证数据准确到达预定的程序。一个端口不能同时被多个应用程序占用,一个应用程序结束以后,端口不会立即释放,有一个内存延迟占有的时间,这个时间一般很短。端口、0-1023已经被系统应用程序及其他应用程序占用,程序设计时避免使用这个范围的端口。
7.套接字Socket
套接字是数据发送与接收的工具。发送者通过套接字发送数据,接受者通过套接字监听指定的端口获取数据。
8.无论采用TCP协议,还是UDP协议,数据都只能以字节形式发送。
二 TCP程序设计
1.关闭通过Socket获取的输入流或者输出流将关闭Socket。
2.通过Socket获取的输出流输出完毕后必须关闭,不然另一端对应的输入流将阻塞。由于通过输出流对象关闭输出流时,同时关闭Socket对象,将导致另一端无法获取对应Socket的对象,因此只能通过Socket下的方法shutdownOutput关闭输出流。
3.客户端的一般步骤:
Socket socket=new Socket(String host,int port);//创建客户端Socket,发送与接收数据,需要指明服务器IP与端口 OutputStream os=socket.getOutputStream();//获取输出流,向服务器发送数据 .......... os.flush(); socket.shutdownOutput();//关闭输出流,防止服务器端阻塞 InputStream is=socket.getInputStream();//获取输入流,输入流包含服务器的反馈信息 ............ socket.close();//关闭socket,同时关闭输入与输出流
4.服务器的一般步骤:
ServerSocket server=new ServerSocket(int port);//建立服务器端套接字,指定监听端口 Socket socket=server.accept();//获取访问客户端的Socket,阻塞线程 InputStream is=socket.getInputStream();//获取输入流,其中包含客户端发送的数据 ............. OutputStream os=socket.getOutputStream();//获取输出流,向客户端反馈信息 .............. os.flush(); os.shutdownOutput(); server.close();
5.Demo
客户端
package com.javase.networkCommunication.tcp.demo02; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class ImgClient { public static void main(String[] args) throws UnknownHostException, IOException { Socket socket = new Socket("192.168.146.1", 10007); FileInputStream is = new FileInputStream("Files/1.jpg"); OutputStream os = socket.getOutputStream(); byte[] buf = new byte[1024];// 先将数据读取到缓冲区,比频繁的从硬盘读取速度快 int length = 0; while ((length = is.read(buf)) != -1) { os.write(buf, 0, length); } os.flush(); socket.shutdownOutput();// 如果输出流不关闭,服务端对应的输入流会阻塞 InputStream replyIs = socket.getInputStream();//不会阻塞线程 byte[] buf01 = new byte[1024]; int length01 = replyIs.read(buf01); String reply = new String(buf01, 0, length01); System.out.println(reply); is.close(); socket.close(); } }
服务器
package com.javase.networkCommunication.tcp.demo02; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import org.junit.Test; public class ImgServer { @Test public void test01() throws IOException { ServerSocket serverSocket = new ServerSocket(10007); Socket socket = serverSocket.accept();// 线程阻塞,等待请求 System.out.println("hostAddress=" + socket.getInetAddress().getHostAddress()); InputStream is = socket.getInputStream(); FileOutputStream os = new FileOutputStream("Files/2.jpg"); System.out.println(1); byte[] buf = new byte[1024]; int length = 0; System.out.println(2); int count = 3; while ((length = is.read(buf)) != -1) { os.write(buf, 0, length); System.out.println(count++); } os.flush(); os.close(); System.out.println("图片上传结束"); /*PrintWriter out = new PrintWriter(socket.getOutputStream(), true); out.write("success");*/ OutputStream out = socket.getOutputStream(); out.write("success".getBytes()); out.flush(); socket.shutdownOutput(); System.out.println("响应数据已发出"); serverSocket.close(); } }
三 UDP程序设计
1.数据处理方式
UDP协议以数据包的形式发送数据,每个包的最大值64k。
2.发送数据的一般步骤:
DatagramSocket socket=new DatagramSocket();//创建数据报套接字用于发送数据 //DUP协议采用数据包分段发送数据,因此需要建立数据包,在数据包中指明目的地IP与端口 DatagramPacket packet= DatagramPacket(byte buf[], int offset, int length,InetAddress address, int port); socket.send(packet);
3.接收数据的一般步骤:
DatagramSocket socket=new DatagramSocket(int port);//创建监听指定端口的数据报套接字 DatagramPacket packet=new DatagramPacket(byte buf[], int length); socket.receive(packet);