计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
网络通信协议,可以比喻成大家都说普通话,所以我们可以正常的交流。但如果我们每个人都说一种方言,那么就会导致我们听不懂对方的意思,也无法交流。
1.OSI的体系结构
(从高到低)应用层—表示层—会话层—运输层—网络层—数据链路层—物理层
2.TCP/IP的体系结构
应用层——运输层(TCP或UDP)——网际层IP——网络接口层
3.五层协议的体系结构(两个协议的折中结构)
应用层——运输层——网络层——数据链路层——物理层
进行数据交换,信息交流等,完成不同ip地址的主机之间的通信
如果实现网络中的主机之间的相互通信
利用ip地址在网络中找到这台主机,然后用端口号找到具体的应用程序
//InetAddress类 表示Internet协议(IP)地址package TCPDemo;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressDemo1 {public static void main(String[] args) {try{//查询本机地址InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");System.out.println(inetAddress1);InetAddress inetAddress2 = InetAddress.getByName("localhost");System.out.println(inetAddress2);InetAddress inetAddress3 = InetAddress.getLocalHost();System.out.println(inetAddress3);//查询网站ip地址InetAddress inetAddress4 = InetAddress.getByName("www.baidu.com");System.out.println(inetAddress4); //www.baidu.com/14.215.177.39//常用方法//获取该网站的ip地址System.out.println(inetAddress4.getHostAddress()); //14.215.177.39//获取该网站的域名System.out.println(inetAddress4.getHostName()); //www.baidu.com}catch(UnknownHostException e){e.printStackTrace();}}
}
结果为
可以通过 netstat -ano 查看所有的端口
可以通过 netstat -ano|findstr “端口号” 查看指定的端口
package TCPDemo;
import java.net.InetSocketAddress;
public class InetSocketAddressDemo1 {public static void main(String[] args) {InetSocketAddress address1 = new InetSocketAddress("127.0.0.1",8080);InetSocketAddress address2 = new InetSocketAddress("localhost",8080);System.out.println(address1); // /127.0.0.1:8080System.out.println(address2); // localhost/127.0.0.1:8080System.out.println(address1.getAddress()); // /127.0.0.1//获取地址System.out.println(address1.getHostName()); // 127.0.0.1//获取端口System.out.println(address1.getPort()); // 8080}
}
TCP
TCP的服务端和客户端建立连接的过程可以看这篇博客
java通信一:Socket通信原理简单理解
这里用B站up @遇见狂神说的比喻,我觉得很生动形象
A是客户端,B是服务端
A:你瞅啥
B:瞅你咋地
A:打一架
翻译一下也就是
A先跟B沟通,希望建立连接
然后B要回应A,可以建立连接,然后确定A还在不在
A再回应B
这样三次握手,就可以建立连接了
A:我要断开连接了
B:我知道你要断开了(询问第一遍)
B:你真的要断开吗(再次确认一遍)
A:我真的要断开了
————————
UDP
客户端将字符串hello传入到服务端
package TCPDemo;import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;//客户端
public class TCPClientDemo1 {public static void main(String[] args) {Socket socket = null;try {// 1.要知道服务器的地址,端口号InetAddress serverIP = InetAddress.getByName("127.0.0.1");int port = 9999;// 2.创建一个socket连接socket = new Socket(serverIP,port);// 3.发送消息 用IO流的方式/*客户端上的使用1.getInputStream方法可以得到一个输入流,客户端的Socket对象上的getInputStream方法得到输入流其实就是从服务器端发回的数据。2.getOutputStream方法得到的是一个输出流,客户端的Socket对象上的getOutputStream方法得到的输出流其实就是发送给服务器端的数据。*/OutputStream os = socket.getOutputStream();os.write("hello".getBytes());} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if(socket!=null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}
package TCPDemo;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;//服务端
public class TCPServerDemo1 {public static void main(String[] args) {//在这里初始化是为了在finally中关闭资源ServerSocket serverSocket = null;Socket socket = null;InputStream is = null;ByteArrayOutputStream baos = null;try {//1. 服务端首先要有一个地址//这里的端口号是自己编的,ip地址用的本地地址127.0.0.1serverSocket = new ServerSocket(9999);//2. 等待客户端的连接//这里的socket对象和客户端里面的socket对象是一个对象,只不过写到两个类里面//accept()方法是监听客户端连接过来的socket,并返回一个socket//服务端与客户端建立连接,用的是这一个socket连接,所以两个对象相同socket = serverSocket.accept();// 3.读取客户端的消息/*服务器端上的使用1.getInputStream方法得到的是一个输入流,服务端的Socket对象上的getInputStream方法得到的输入流其实就是从客户端发送给服务器端的数据流。2.getOutputStream方法得到的是一个输出流,服务端的Socket对象上的getOutputStream方法得到的输出流其实就是发送给客户端的数据。*/is = socket.getInputStream();//具体读取数据有两种方式//方式一,常规的,只用InputStream/*byte[] buffer = new byte[1024];int len;//将数据读入缓冲区数组buffer中,再将buffer数组转为字符串while((len=is.read(buffer))!=-1){String s = new String(buffer, 0, len);System.out.println(s);}*///方式二,用ByteArrayOutputStream//is.read(buffer)将客户端的数据读入到buffer缓冲数组中//再用ByteArrayOutputStream将buffer数组中的数据写入自己的字节数组缓冲区//这样做的好处是可以避免乱码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());/*//这样可以一直接收客户端发来的消息while(true){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{//关闭资源//注意关闭的顺序if(baos!=null){try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}if(is!=null){try {is.close();} catch (IOException e) {e.printStackTrace();}}if(socket!=null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}if(serverSocket!=null){try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}}
}
运行时,先运行服务端
后运行客户端
最后在服务端的输出窗口看到字符串
将服务端的代码改成while循环结构,就可以让服务端一直接收客户端发来的消息,客户端运行几次,服务端打印几条消息
package TCPDemo;/*** 这是客户端的代码,作用是将图片文件picture.jpg传入服务端* 文件传入完毕后,立刻开始接收服务端传来的消息*/import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;public class TCPClientDemo2 {public static void main(String[] args) throws IOException {//1.创建一个Socket链接Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9999);//2.创建一个输出流OutputStream os = new FileOutputStream("picture/picture.jpg");//3.读取文件FileInputStream fis = new FileInputStream("picture/picture.jpg");//4.写出文件byte[] buffer = new byte[1024];int len;while((len=fis.read(buffer))!=-1){os.write(buffer,0,len);}//通知服务器,我已经传输完毕了socket.shutdownOutput();//确定服务器接收完毕,才能断开连接InputStream inputStream = socket.getInputStream();//用ByteArrayOutputStream将inputStream里面的数据写出来//ByteArrayOutputStream里面的缓冲区是字节数组,这样保证不会格式转换错误ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] bytes = new byte[1024];int len1;while((len1=inputStream.read(bytes))!=-1){baos.write(bytes,0,len1);}System.out.println(baos.toString());//5.关闭流baos.close();inputStream.close();fis.close();os.close();socket.close();}
}
package TCPDemo;/*** 这是服务端的代码,作用是接收客户端传来的文件* 然后将文件写入本地文件夹当中* 文件写入完毕后,给客户端发送消息*/import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class TCPServerDemo2 {public static void main(String[] args) throws IOException {//1.创建服务ServerSocket serverSocket = new ServerSocket(9999);//2.监听客户端的连接Socket socket = serverSocket.accept();//获取输入流InputStream is = socket.getInputStream();//文件输出FileOutputStream fos = new FileOutputStream(new File("picture/picture1.jpg"));byte[] buffer = new byte[1024];int len;while((len=is.read(buffer))!=-1){fos.write(buffer,0,len);}//通知客户端我接收完毕了OutputStream outputStream = socket.getOutputStream();outputStream.write("ok".getBytes());//关闭资源outputStream.close();fos.close();is.close();socket.close();serverSocket.close();}
}
运行结果
package TCPDemo;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;//UDP不需要连接服务器,所以这里也没有区分Client和Server
public class UDPDemo1 {public static void main(String[] args) throws IOException {// 1.建立一个Socket连接//如果这里DatagramSocket socket = new DatagramSocket(8080);//那么UDPDemo2也可以发送包到这个8080端口,然后UDPDemo1也可以接收包//所以说UDP没有明显区分客户端和服务端DatagramSocket socket = new DatagramSocket();// 2. 建立一个包String msg = "hello";//发送给谁InetAddress localhost = InetAddress.getByName("localhost");int port = 9090;// 参数含义:第一个参数是数据,中间两个参数是数据长度的起点与终点,最后两个参数是要发送给谁DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,port);// 3. 发送包socket.send(packet);//这段代码的主体步骤是第一、三步,即建立连接然后发送包//中间的步骤都是在创建包// 4.关闭流socket.close();}
}
package TCPDemo;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;//这里用来接收UDPDemo1 发送的包,但是这里不是服务器
//同样可以用UDPDemo2 来给UDPDemo1 发送包
//UDPDemo2 相当于一直在监听状态,直到UDPDemo1将包发送过来
public class UDPDemo2 {public static void main(String[] args) throws IOException {//开放端口,如果不建立Socket连接,那么UDPDemo1怎么发包都没用,因为没有人接收DatagramSocket socket = new DatagramSocket(9090);//接收数据包byte[] buffer = new byte[1024];DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);socket.receive(packet); //阻塞接收,也就说直到成功接收前,都一直存活//获取发送方的ip地址System.out.println(packet.getAddress().getHostAddress());//输出接收到的包里面的数据System.out.println(new String(packet.getData(),0,packet.getLength()));//关闭连接socket.close();}
}
结果为