网络架构模型主要有OSI模型和TCP/IP模型java
OSI(Open System Interconnect),开放式系统互联。OSI定义了网络互连的七层框架(物理层、数据链路层、网络层、传输层、会话层、表示层、应用层)。它实际上并无人推广,只是一种理想化的模型。程序员
应用层编程
应用层最靠近用户的一层,是为计算机用户提供应用接口,也为用户直接提供各类网络服务。咱们常见应用层的网络服务协议有:HTTP,HTTPS,FTP,TELNET等。浏览器
传输层服务器
创建了主机端到端的连接,传输层的做用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。该层向高层屏蔽了下层数据通讯的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户控制和设定的、可靠的数据通路。咱们一般说的,TCP UDP就是在这一层。端口号既是这里的“端”。网络
网络层多线程
本层经过IP寻址来创建两个节点之间的链接,为源端的运输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层。就是一般说的IP层。这一层就是咱们常常说的IP协议层。IP协议是Internet的基础。架构
数据链路层框架
物理层socket
即浏览器/服务器模式,B/S架构采起浏览器请求,服务器响应的工做模式。客户则在须要服务时向服务器进行请求。服务器响应后及时返回,不须要实时监听端口。
即客户端/浏览器模式,通讯双方一方做为服务器等待客户提出请求并予以响应。客户则在须要服务时向服务器提出申请。服务器通常做为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时本身继续监听服务端口,使后来的客户也能及时获得服务。
传输控制协议(TCP,Transmission Control Protocol)是一种面向链接的、可靠的、基于字节流的传输层通讯协议。
经过TCP协议传输,获得的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须创建链接,当一个socket(一般都是server socket)等待创建链接时,另外一个socket能够要求进行链接,一旦这两个socket链接起来,它们就能够进行双向数据传输,双方均可以进行发送或接收操做。
创建起一个TCP链接须要通过“三次握手”:
第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时本身也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
握手过程当中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。
理想状态下,TCP链接一旦创建,在通讯双方中的任何一方主动关闭链接以前,TCP 链接都将被一直保持下去。
断开链接时服务器和客户端都可以主动发起断开TCP链接的请求。
UDP 为应用程序提供了一种无需创建链接就能够发送封装的 IP 数据包的方法。
每一个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,所以可否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
TCP
UDP
Socket的英文原义是“孔”或“插座”。在网络编程中,网络上的两个程序经过一个双向的通讯链接实现数据的交换,这个链接的一端称为一个Socket。
Socket套接字是通讯的基石,是支持TCP/IP协议的网络通讯的基本操做单元。它是网络通讯过程当中端点的抽象表示,包含进行网络通讯必须的五种信息:链接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
Socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员作网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通讯的能力。
套接字之间的链接过程能够分为三个步骤:服务器监听,客户端请求,链接确认。
Server端Listen监听某个端口是否有链接请求,Client端向Server 端发出链接请求,Server端向Client端发回Accept接受消息。这样一个链接就创建起来了。Server端和Client端均可以经过Send,Write等方法与对方通讯。
对于一个功能齐全的Socket,都要包含如下基本结构,其工做过程包含如下四个基本的步骤:
客户端
import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.nio.charset.StandardCharsets; //客户端 public class TCPClient01 { public static void main(String[] args) { Socket socket = null; OutputStream os = null; try { //一、要知道服务器的地址 InetAddress serverIp = InetAddress.getByName("127.0.0.1"); //二、端口号 int port = 9999; //三、建立一个Socket链接 socket = new Socket(serverIp, port); //四、发送消息 os = socket.getOutputStream(); os.write("你好,欢迎光临喵小决".getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { e.printStackTrace(); }finally { try { assert os != null; os.close(); } catch (IOException e) { e.printStackTrace(); } try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
服务端
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; //服务端 public class TCPServer01 { public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket = null; InputStream is = null; ByteArrayOutputStream baos = null; try { //一、拥有一个地址 serverSocket = new ServerSocket(9999); //二、等待客户端链接过来 socket = serverSocket.accept(); //三、读取客户端的消息 is = socket.getInputStream(); //管道流 baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { baos.write(buffer, 0, len); } System.out.println(baos.toString()); } catch (IOException e) { e.printStackTrace(); }finally { //关闭资源 try { assert baos != null; baos.close(); } catch (IOException e) { e.printStackTrace(); } try { is.close(); } catch (IOException e) { e.printStackTrace(); } try { socket.close(); } catch (IOException e) { e.printStackTrace(); } try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
客户端
import java.io.*; import java.net.InetAddress; import java.net.Socket; //客户端 public class TCPClient02 { public static void main(String[] args) throws Exception { //一、建立一个Socket链接 Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000); //二、建立一个输出流 OutputStream os = socket.getOutputStream(); //三、文件流 FileInputStream fis = new FileInputStream(new File("D:\\Project\\java\\TCP\\TCP\\src\\bg.png")); //四、写出文件 byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { os.write(buffer, 0, len); } //通知服务器,我已经结束了 socket.shutdownOutput();//我已经传输完了 //肯定服务器接收完毕,才可以断开链接 InputStream is = socket.getInputStream(); //String byte[] ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer2 = new byte[1024]; int len2; while ((len2 = is.read(buffer2)) != -1) { baos.write(buffer2, 0, len2); } System.out.println(baos.toString()); //五、关闭资源 baos.close(); is.close(); fis.close(); os.close(); socket.close(); } }
服务端
import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; //服务端 public class TCPServer02 { public static void main(String[] args) throws Exception { //一、建立服务 ServerSocket serverSocket = new ServerSocket(9000); //二、监听客户端的链接 Socket socket = serverSocket.accept();//阻塞式监听,会一直等待客户端链接 //三、获取输入流 InputStream is = socket.getInputStream(); //四、文件输出 FileOutputStream fos = new FileOutputStream(new File("receive.png")); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } //通知客户端我接受完毕了 OutputStream os = socket.getOutputStream(); os.write("我接收完毕了,你能够断开了".getBytes(StandardCharsets.UTF_8)); //关闭资源 fos.close(); is.close(); socket.close(); serverSocket.close(); } }
客户端
import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; //不须要链接服务器 public class UdpClient01 { public static void main(String[] args) throws Exception { //一、创建一个Socket DatagramSocket socket = new DatagramSocket(); //二、建一个包 String msg = "你好!,服务器"; //发送给谁 InetAddress localhost = InetAddress.getByName("localhost"); int port = 9090; //数据,数据的长度起始,要发送给谁 DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port); //三、发送一个包 socket.send(packet); //四、关闭流 socket.close(); } }
服务器
import java.net.DatagramPacket; import java.net.DatagramSocket; //仍是要等待客户端的链接 public class UdpServer01 { public static void main(String[] args) throws Exception { //开放端口 DatagramSocket socket = new DatagramSocket(9090); //接收数据包 byte[] buffer = new byte[1024]; //接收 DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); socket.receive(packet);//阻塞接收 System.out.println(new String(packet.getData(),0,packet.getLength())); //关闭 socket.close(); } }
发送方
import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; public class UdpSender { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(8888); //准备数据:控制台读取System.in BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); while (true) { String data = reader.readLine(); byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8); DatagramPacket packet = new DatagramPacket(dataBytes, 0, dataBytes.length, new InetSocketAddress("localhost", 6666)); socket.send(packet); if (data.equals("bye")) { break; } } socket.close(); } }
接收方
import java.net.DatagramPacket; import java.net.DatagramSocket; public class UdpReceive { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(6666); while (true) { //准备接收的包裹 byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); socket.receive(packet);//阻塞式接收包裹 //断开链接 bye byte[] data = packet.getData(); String receiveData = new String(data, 0, data.length); System.out.println(receiveData); if (receiveData.equals("bye")) { break; } } socket.close(); } }
使用Socket
和Thread
来实现多线程在线质询聊天
老师
public class TalkTeacher { public static void main(String[] args) { new Thread(new TalkSend(6666, "localhost", 8888)).start(); new Thread(new TalkReceive(9999, "学生")).start(); } }
学生
public class TalkStudent { public static void main(String[] args) { new Thread(new TalkSend(7777, "localhost", 9999)).start(); new Thread(new TalkReceive(8888, "老师")).start(); } }
发送方
import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; public class UdpSender { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(8888); //准备数据:控制台读取System.in BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); while (true) { String data = reader.readLine(); byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8); DatagramPacket packet = new DatagramPacket(dataBytes, 0, dataBytes.length, new InetSocketAddress("localhost", 6666)); socket.send(packet); if (data.equals("bye")) { break; } } socket.close(); } }
接收方
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class TalkReceive implements Runnable { DatagramSocket socket = null; private int port; private String msgFrom; public TalkReceive(int port, String msgFrom) { this.msgFrom = msgFrom; this.port = port; try { socket = new DatagramSocket(port); } catch (SocketException e) { e.printStackTrace(); } } @Override public void run() { while (true) { try { byte[] container = new byte[1024]; DatagramPacket packet = new DatagramPacket(container, 0, container.length); socket.receive(packet); byte[] data = packet.getData(); String receiveData = new String(data, 0, data.length); System.out.println(msgFrom + ":" + receiveData); if (receiveData.equals("bye")) { break; } } catch (IOException e) { e.printStackTrace(); } } socket.close(); } }