一、计算机网络
1、简介
计算机网络,是把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多计算机可以方便的相互传递信息,共享硬件、软件、数据等资源。计算机网络提供如下功能:
资源共享
信息传输和集中分布
均衡负荷和分布处理
综合信息服务
实现计算机网络条件
ip、端口
协议
http,upd,tcp/ip
硬件支持
软件支持
2、网络范围
按照规模大小和延伸范围可以分为:局域网、城域网、广域网,其中Internet 是最大的广域网。
按照网络的拓扑结构可以分为:星型网络、总线网络、环线网络、树形网络、星型环线网络等。
按照网络的传播介质可以分为:双绞线网、同轴电缆网、光纤网和卫星网等。
3、网络协议
OSI七层模型
TCP、UDP都是属于传输层
TCP、UDP都是依赖于ip
Http属于应用层
依赖于tcp/ip 协议实现
二、ip和端口
1、IP概述
IP 地址用于唯一地表示网络中的一个通信实体。基于 IP 协议网络中传输的数据包,都必须使用IP 地址来进行标识。
2、端口号
端口主要跟应用有关
三、InetAddress用法
1、简介
通过此对象,获取ip地址及主机名、获取ip状态
2、举例
package IP地址;import java.io.IOException;import java.net.InetAddress;import java.net.UnknownHostException;public class MainTest { public static void main(String[] args) { // TODO Auto-generated method stub //获取本机的ip地址和IP名 try { //返回本地主机的地址 InetAddress ipAddress = InetAddress.getLocalHost(); //ip地址用byte数组装,原始ip地址 System.out.println("原始ip地址******************"); byte[] ipBuf = ipAddress.getAddress(); for(byte v:ipBuf) { System.out.print(v+"\t"); } System.out.println("调用getHostAddress方法,打印出192.。。。。的形式,返回String类型"); String str = ipAddress.getHostAddress(); System.out.println("ip地址为:"+str); System.out.println("获取此ip地址的主机名**********"); System.out.println(ipAddress.getHostName()); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("根据主机获取对应的InetAddress对象******************"); try { InetAddress inetAddress = InetAddress.getByName("www.bilibili.com"); //InetAddress inetAddress = InetAddress.getByName("192.168.137.1"); //判断是否可以到达 System.out.println(inetAddress.isReachable(100)); //输出可连接到ip地址 System.out.println(inetAddress.getHostAddress()); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }}}
四、TCP/IP协议
1、简介
TCP/IP通信协议是一种可靠的网络协议
通过TCP/IP协议实现数据传输,保证数据不丢失,对方肯定可以稳定接到数据
可靠
特点
socket.getInputStream():读数据
socket.getOutputStream():写数据
server(服务端)
client(客户端)
四次挥手
三次握手
它是面向对象连接的协议
关闭连接
TCP/IP协议它是针对客户端(client)、服务端(Server)而言的
当连接成功之后,建立网络虚拟链路,此链路其实就是网络IO流,生成一个端点,此端点就是Socket(套接口),通过Socket获取IO流的输入和输出
2、tcp/ip工作原理
工作步骤
客户端与服务端面向连接
三次握手
所谓三次握手(Three-Way Handshake)即建立TCP连接,是指建立一个TCP连接时,需要客户端和务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发
建立连接关系之后,产生网络虚拟链路,就是网络IO流(SocketStream)
如何实现数据通讯
获取针对客户端而言的,获取输入流,读数据
InputStream inputstream=socket.getInputStream();
读数据
inputstream.read(buf);
获取针对客户端而言,获取输出流
OutputStream outPutStram=socket.getOutputStream()
写数据
outPutStream.write(xxx);
客户端发送数据给服务端
服务端发送数据给客户端
关闭连接
四次挥手
五、第一个tcp/ip实例
需求
服务端发送字符串给客户端
1、创建TCP服务器端
package 第一个tcpip实例;import java.io.IOException;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;/* * 编写一个tcpip的服务端程序 * */public class TcpIpServer { //定义端口 public static final int PORT=30001; public static void main(String[] args) { //创建ServerSocket对象 //创建tcpip服务端程序的类对象 ServerSocket ss=null; try { ss=new ServerSocket(PORT); //调用一个方法 //它是一个阻塞方法,等待客户端的连接,客户端一有连接,立即返回socket对象 System.out.println("accept start"); Socket socket=ss.accept(); System.out.println("accept end socket ip="+socket.getInetAddress().getHostAddress()); //服务端发送字符串“hello world”给客户端接受 //获取输出流对象 OutputStream outputStream=socket.getOutputStream(); //写数据 byte buf[]="hello world".getBytes(); outputStream.write(buf); outputStream.flush(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }}}
2、创建TCP客户端
package 第一个tcpip实例;import java.io.IOException;import java.io.InputStream;import java.net.Socket;public class TcpIpClient { public static void main(String[] args) { //针对tcpip的服务端,进行连接 //创建Socket对象 try { Socket ss=new Socket("192.168.59.90", TcpIpServer.PORT); //客户端读取服务端发送过来的数据 InputStream inStream=ss.getInputStream(); byte []buf=new byte[32]; int readLen=inStream.read(buf); String receiveMessage=new String(buf,0,readLen); System.out.println("接受服务端发送过来的数据="+receiveMessage); //关闭tcpip的连接 ss.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }}}
3、第二个TCP实例
需求
客户端与服务端可以相互收发数据
实例
package 第二个tcpip实例;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;public class Server { public final static int PORT=30004; public static void main(String[] args) { //创建ServerSocket ServerSocket ss=null; try { ss=new ServerSocket(PORT); //等待客户端的连接,此accept方法是等待、阻塞方法 Socket socket=ss.accept(); //发送数据给客户端 OutputStream outputStream=socket.getOutputStream(); outputStream.write("欢迎光临!".getBytes()); outputStream.flush(); //接受客户端发送过来的数据 InputStream inStream=socket.getInputStream(); byte buf[]=new byte[32]; int readLen=inStream.read(buf); System.out.println("接受客户端发送过来的数据="+new String(buf,0,readLen)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }}}
package 第二个tcpip实例;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.net.UnknownHostException;public class Client { public static void main(String[] args) { Socket socket=null; try { socket=new Socket("192.168.59.90",Server.PORT); InputStream inputStream=socket.getInputStream(); //定义buf数组 byte buf[]=new byte[32]; int readLen=inputStream.read(buf); //获取数据 String recMessage=new String(buf,0,readLen); System.out.println("recMessage="+recMessage); //客户端又发送数据给服务端 OutputStream outputStream=socket.getOutputStream(); outputStream.write("我已经收到".getBytes()); outputStream.flush(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(socket!=null) { try { socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }}}
客户端
服务端
4、第三个实例
需求
实现点对点的tcpip聊天功能
所需技术
网络编程
IO流
多线程
代码实现
编写服务端程序
package 第三个tcpip实例;import java.io.IOException;import java.io.OutputStream;import java.io.PrintStream;import java.net.ServerSocket;import java.net.Socket;import java.util.Scanner;public class TcpIpChatServer { public static final int PORT=30005; //获取键盘内容 private static Scanner sc=new Scanner(System.in); public static void main(String[] args) throws IOException { //创建tcpip的Server端的对象 ServerSocket ss=new ServerSocket(PORT); //等待监听客户端的连接 Socket socket=ss.accept(); System.out.println("有客户端连接,客户端ip="+socket.getInetAddress().getHostAddress()); //获取输出流的对象 OutputStream outputStream=socket.getOutputStream(); //创建一个打印流 PrintStream ps=new PrintStream(outputStream); /* * 可以通过主线程实现写功能 * */ System.out.println("退出输入按q,请输入发送给客户端的内容:"); //定义发送消息的变量 String sendMessage=null; while((sendMessage=sc.nextLine())!=null) { if(sendMessage.equals("q")) { //退出聊天 break; } ps.println(sendMessage); ps.flush(); }} /* * 实现读线程 * */}
编写客户端程序
package 第三个tcpip实例;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;import java.net.UnknownHostException;public class TcpIpChatClient { public static void main(String[] args) throws UnknownHostException, IOException { //创建Socket对象 Socket socket=new Socket("192.168.59.90", TcpIpChatServer.PORT); //创建一个专门处理读数据的线程 new TcpIpChatClient().new ReadDataThread(socket).start();} //定义一个读数据的线程类 public class ReadDataThread extends Thread{ private Socket socket; private BufferedReader br; public ReadDataThread(Socket socket) throws IOException { this.socket=socket; //将输入流装饰成缓存流来读取数据 //将inputstream---->inputStreamReader(转换流)---->bufferReader br=new BufferedReader(new InputStreamReader(socket.getInputStream())); } /* * 可以在子线程的执行体读取数据 * */ @Override public void run() { String receveMessage=null; //读数据 try { while((receveMessage=br.readLine())!=null) { System.out.println("接受服务端发送过来的数据="+receveMessage); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}}
5、第四个实例
需求
实现聊天室
编写服务器
package 聊天群;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;import java.util.List;public class Server { public static final int PORT = 11111; //定义一个集合,存储Socket对象 private static List<Socket> socketList = new ArrayList<>(); public static void main(String[] args) throws IOException { // TODO Auto-generated method stub //创建ServerSocket对象 ServerSocket ss = new ServerSocket(PORT); System.out.println("服务器已经启动"); //监听客户端的连接 //一个socket对象对应一个客户端,不断监听客户端的连接 while(true) { Socket socket = ss.accept(); socketList.add(socket); System.out.println("接收客户端连接,并且启动子线程 客户端ip:"+socket.getInetAddress().getHostAddress()); //创建子线程,每个Socket对象,对应一个子线程 new Server().new ReadClientDataThread(socket).start(); }} /* * 读取数据的线程 * */ class ReadClientDataThread extends Thread{ private Socket socket; private BufferedReader br; public ReadClientDataThread(Socket socket) throws IOException { this.socket = socket; br=new BufferedReader(new InputStreamReader(socket.getInputStream())); } @Override public void run() { //不断读取客户端数据 String recMessage=null; //获取客户端发送过来的数据,要将数据分发其它的客户端 //因此首先要获取其它客户端的Socket对象,当前socket对象保存在集合对象里面 //遍历存储socket对象的集合 try { while((recMessage=br.readLine())!=null) { //获取客户端发送过来的数据,要将数据分发其它的客户端 //因此首先要获取其它客户端的Socket对象,当前socket对象保存在集合对象里面 //遍历存储socket对象的集合 for(Socket sc:socketList) { //封装打印流(PrintStream) PrintStream ps=new PrintStream(sc.getOutputStream()); //将数据写到另外的客户端 ps.println(recMessage); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}}
编写客户端
package 聊天群;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;import java.net.UnknownHostException;import java.util.Scanner;import java.io.OutputStream;public class ChatClient { // 获取键盘内容 private static Scanner sc = new Scanner(System.in); public static void main(String[] args) throws UnknownHostException, IOException { // 创建Socket对象 Socket socket = new Socket("192.168.59.21",Server.PORT); // 创建一个专门处理读数据的线程 new ChatClient().new ReadDataThread(socket).start(); // 获取输出流的对象 OutputStream outputStream = socket.getOutputStream(); // 创建一个打印流 PrintStream ps = new PrintStream(outputStream); /* * 可以通过主线程实现写功能 */ System.out.println("退出输入按q,请输入发送给服务端的内容:"); // 定义发送消息的变量 String sendMessage = null; while ((sendMessage = sc.nextLine()) != null) { if (sendMessage.equals("q")) { // 退出聊天 break; } ps.println(sendMessage); ps.flush(); } System.out.println("主线程结束"); sc.close();} // 定义一个读数据的线程类 public class ReadDataThread extends Thread { private Socket socket; private BufferedReader br; public ReadDataThread(Socket socket) throws IOException { this.socket = socket; // 将输入流装饰成缓存流来读取数据 // 将inputstream---->inputStreamReader(转换流)---->bufferReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); } /* * 可以在子线程的执行体读取数据 */ @Override public void run() { String receveMessage = null; // 读数据 try { while ((receveMessage = br.readLine()) !=null) { System.out.println("接受服务端发送过来的数据=" + receveMessage); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}}
六、UDP协议
1、简介
UDP协议:用户数据报协议
udp协议它是基于数据报,以数据报为单位来传输
传输的是不可靠的数据协议
传输过程中可能存在丢失
非面向连接协议
他没有很明确的客户端、服务端之分
2、UDP协议的优缺点
缺点:
数据传输不可靠
优点:
数据传输速度快
作用域
视频传输(高效,实时的效果)
游戏
3、UDP协议传输原理
udp协议它是以数据报(packet)为单位传输,它只管发送,不管你是否接收成功,它是没有应答机制(ack机制)
数据报包括
目标ip
端口
数据部分
报头
4、UDP核心类
1、DatagramSocket
发送、接收数据
DatagramSocket的构造器
DatagramSocket(port):绑定端口,创建接收方
DatagramSocket():没有绑定端口,它是发送方
receive(DatagramPacket p):接收数据
send(DatagramPacket p):发送数据
2、DatagramPacket
此类描述数据报内容
数据部分
ip部分
端口
分析DatagramPacket的构造器
起始位置是offer,长度为length的字节数组接收数据报
将长度为length的字节数组发送到目标主机的ip及端口
用来接收长度为length的数据报
DatagramPacket(byte[] buf,int length):肯定属于接收数据报的对象,构造
DatagramPacket(byte[] buf,int length,InetAddress address,int port):用来发送数据报 的对象
DatagramPacket(byte[] buf,int offest, int length)
3、举例
package udp协议;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import org.junit.Test;public class UDPTest { //发送端 @Test public void testSender() throws IOException { //创建DatagramSocket对象,作为发送方,不需要绑定端口 DatagramSocket socket = new DatagramSocket(); String str = "我是UDP方式发送的数据"; byte[] data = str.getBytes(); InetAddress inet = InetAddress.getLocalHost(); //定义数据报 DatagramPacket packet = new DatagramPacket(data,0,data.length,inet,9000); //发送数据报 socket.send(packet); socket.close();} //接收端 @Test public void testReceiver() throws IOException { //创建DataDatagramSocket,绑定端口,属于接收端 DatagramSocket socket = new DatagramSocket(9000); byte[] buffer = new byte[100]; //创建DatagramPacket对象,它是属于接收数据报,将数据报的内容存储到buf数组中去 DatagramPacket packet = new DatagramPacket(buffer, 0,buffer.length); //调用receiver方法接收数据,它是一个阻塞方法 //将接受的数据存储到数据报中 socket.receive(packet); //将数据报的字节数组转化成String字符串型 //packet.getData();//接收到的数据 System.out.println(new String(packet.getData(),0,packet.getLength())); socket.close();}}
5、编写第二个实例
需求
基于UDP协议的实现点对点的聊天功能
所需要技术
UDP协议
多线程实现
举例
package UDP点对点聊天;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.util.Scanner;public class A { private static Scanner sc = new Scanner(System.in); public static final int PORT=30001; public static void main(String[] args) throws IOException { // TODO Auto-generated method stub //定义发送方的DatagramSocket对象 DatagramSocket sendDS = new DatagramSocket(); //定义接收方的DatagramSocket对象,绑定端口 DatagramSocket receiveDS = new DatagramSocket(PORT); //启动子线程,接收数据 new A().new ReadDataThread(receiveDS).start(); /* * 主线程负责发送数据 * */ System.out.println("请输入发送给B主机的内容(退出按n):"); String sendMessage = null; while((sendMessage=sc.next())!=null) { if(sendMessage.equals("n")) { System.out.println("结束聊天!"); break; } //创建DatagramPackage对象(发送包),绑定ip和端口 DatagramPacket sendPacket = new DatagramPacket(sendMessage.getBytes(), sendMessage.getBytes().length, InetAddress.getLocalHost(), B.PORT); //发送包 sendDS.send(sendPacket); }} /* * 子线程负责读取数据 * */ public class ReadDataThread extends Thread{ private DatagramSocket receiveDS; public ReadDataThread(DatagramSocket receiveDS) { this.receiveDS = receiveDS; } @Override public void run() { while(true) { byte[] buf = new byte[128]; //创建数据报,属于接收数据的数据报 DatagramPacket dp = new DatagramPacket(buf, buf.length); try { receiveDS.receive(dp); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //将字节数组转换成字符串 String recMessage = new String(dp.getData(), 0, dp.getLength()); System.out.println("接收B主机发送过来的数据:"+recMessage); } }}}
package UDP点对点聊天;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.SocketException;import java.net.UnknownHostException;import java.util.Scanner;public class B { public static final int PORT=30002; private static Scanner sc = new Scanner(System.in); public static void main(String[] args) { // TODO Auto-generated method stub //定义发送方的DatagramSocket对象 try { DatagramSocket sendDS = new DatagramSocket(); //定义接收方的DatagramSocket对象,绑定端口号 DatagramSocket receiveDS = new DatagramSocket(PORT); //启动子线程 new B().new ReceiveThread(receiveDS).start(); /* * 主线程负责发送数据 * */ System.out.println("请输入发送给A主机的内容(退出按n):"); String sendMessage = null; while((sendMessage=sc.next())!=null) { if(sendMessage.equals("n")) { System.out.println("结束聊天!"); break; } //把字符串转化为byte类型 byte[] buf = sendMessage.getBytes(); //创建发送包对象 DatagramPacket sendDP = new DatagramPacket(buf, buf.length, InetAddress.getLocalHost(), A.PORT); sendDS.send(sendDP); } } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }} /* * 创建子线程,负责读取数据 * */ public class ReceiveThread extends Thread{ private DatagramSocket socket; public ReceiveThread(DatagramSocket socket) { this.socket = socket; } @Override public void run() { while(true) { //定义一个字节数组接收数据 byte[] buf = new byte[128]; //创建数据报,用于接收数据 DatagramPacket packet = new DatagramPacket(buf, buf.length); //进行接收 try { socket.receive(packet); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //把接收的字节数据转换为字符串 String str = new String(packet.getData(),0,packet.getLength()); System.out.println("接收A主机发过来的数据:"+str); } }}}