Java基础之网络编程(UDP,TCP)

网络编程概述及介绍:

        计算机网络:实现资源的共享和传递;

        网络编程:实现网络互连的不同计算机上运行的程序间可以进行数据交换;

        网络参考模拟图:
                OSI(开放系统互联)参考模型:                 TCP/IP参考模型:
                        应用层
                        表示层                                                    应用层
                        会话层
                --------------------------------------------------------------
                        传输层                                                    传输层
                --------------------------------------------------------------
                        网络层                                                    网际层
                --------------------------------------------------------------
                        数据链路层                                            主机至网络层
                        物理层

        OSI参考模型介绍:
                物理层:主要作用,传输比特流(这一层的数据叫做比特);
                数据链路层:将物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装(这一层的数据叫做帧);
                网络层:从下层接收到的数据进行IP地址的封装与解封装(工作设备:路由器,这一层的数据叫做数据包);
                传输层:定义了协议和端口号,主要将从下层接收的数据进行分段和传输,到达目的地后再进行重组(这一层的数据叫做段);
                会话层:通过传输层(端口号,传输端口与接收端口)建立数据传输的通道,主要在你的系统之间发起会话或者接收会话请求;
                表示层:主要对数据进行解释,加密与解密,压缩与解压缩等;

                应用层:主要是一些终端的应用(电脑上可以看到的);


InetAddress:类表示互联网协议(IP)地址;

        常用方法:
               public static InetAddress getByName(String host):在给定主机名(也可以是机器名)的情况下确定主机的 IP 地址;

                public String getHostAddress():返回 IP 地址字符串(以文本表现形式);

        举例:

public class InetAddRessDemo {

	public static void main(String[] args) throws UnknownHostException {
		
		//创建InetAddress对象,通过来获取ip地址
		//在知道主机名的情况下
		//InetAddress address = InetAddress.getByName("USER-20171205ZR") ;
		//IP 地址的文本表示形式
		//Ip地址对象
		InetAddress address = InetAddress.getByName("DESKTOP-MN4CGJE") ;
		
		//上面获取到了Ip地址
		//public String getHostAddress()返回 IP 地址字符串(以文本表现形式)。 
		String ip = address.getHostAddress() ;
		System.out.println(ip);		//192.168.10.1
		//public String getHostName()获取此 IP 地址的主机名。
		String name = address.getHostName() ;
		System.out.println(name);	//DESKTOP-MN4CGJE
	}
}


UDP编程:

        特点:
                1> 不需要建立连接通道;
                2> 数据大小有限制;

                3> 不可靠连接 ---> 传输速度快;

        举例:
                发送端:

package org.westos_06;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * 发送端的开发步骤:
 * 	1)创建发送端的Socket对象
 * 	2)创建数据,并打包
 * 	3)调用当前发送端Socket对象中的发送的方法
 * 	4)关闭资源
 *
 */
public class SendDemo {
	
	public static void main(String[] args) throws IOException {
		
		//1)创建发送端的Socket对象
		//DatagramSocket:此类表示用来发送和接收数据报包的套接字。
		//创建DataGramSocket对象
		//构造方法:public DatagramSocket(int port,InetAddress laddr)
		//这个构造方法,里面传递并不是Ip地址的文本形式
		//构造数据报套接字并将其绑定到本地主机上任何可用的端口
		DatagramSocket ds = new DatagramSocket() ;
		
	  	//2)创建数据,并打包
		//DatagramPacket 表示数据报包
		//DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
		/**
		 * 	buf     - 包数据。
			offset  - 包数据偏移量。
			length  - 包数据长度。
			address - 目的地地址。
			port    - 目的地端口号。
		 */
		//有数据
		byte[] bys = "hello,udp,我来了".getBytes() ;
		//获取包数据长度
		int len = bys.length ;
		//获取ip地址对象
		InetAddress address = InetAddress.getByName("192.168.59.1") ;
		//指定端口号
		int port = 10086 ;
		DatagramPacket dp =new DatagramPacket(bys, 0, len, address, port) ;
		
	  	//3)调用当前发送端Socket对象中的发送的方法send();
		/*public void send(DatagramPacket p)
		          throws IOException从此套接字发送数据报包*/
		ds.send(dp);
		
	  	//4)关闭资源*
		ds.close();
	}
}
                接收端:
package org.westos_06;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 *Udp编程的接收端 开发步骤:
 *		1)创建Socket对象
 *		2)创建一个数据报包(接收容器) 
 *		3)调用Socket对象中的接收的方法
 *		4)解析实际传递的数据
 *		5)将解析的数据(ip,数据)展示在控制台上
 *		6)关闭资源
 *注意:
 *接收端不要运行多次,会出现异常:
 *		java.net.BindException: Address already in use: Cannot bind
 *		绑定异常(地址不能再次被绑定)
 *
 *
 *先运行接收端,再运行发送端;
 */
public class ReceiveDemo {

	public static void main(String[] args) throws IOException {
		
		//1)创建Socket对象
		//public DatagramSocket(int port):创建数据报包套接字对象并且将其绑定到本地主机上的指定端口
		DatagramSocket ds = new DatagramSocket(10086);
		
		//2)创建一个数据报包(接收容器) 
		//public DatagramPacket(byte[] buf, int length)
		byte[] bys = new byte[1024] ;
		int len = bys.length ;
		DatagramPacket dp = new DatagramPacket(bys, len) ;
		
		//3)调用Socket对象中的接收的方法
		//public void receive(DatagramPacket p):从此套接字接收数据报包
		ds.receive(dp);//阻塞式方法
		
		//获取ip地址文本形式
		//public InetAddress getAddress() :返回ip地址对象  数据报包类:DataGramPacket的方法;
		InetAddress adress=dp.getAddress();
		String ip=adress.getHostAddress();
		//getAddress():返回某台机器的 IP 地址,返回类型为:InetAddress;
		//getHostAddress():返回 IP 地址字符串(以文本形式表现);
		
		//4)解析实际传递的数据
		//public byte[] getData() :获取缓冲中实际数据(从接收容器中获取)
		byte[] bys2  = dp.getData() ;
		
		//public int getLength()返回将要发送或接收到的数据的长度。
		int len2 = dp.getLength() ;//从接收容器中获取包的实际长度
		
		String data = new String(bys2, 0, len2) ;
		
		System.out.println("当前接收到的数据是:"+data+",来自于"+ip);
		
		//6)关闭资源
		ds.close();
	}
}
        改进接收端和发送端:
        举例:
                发送端:
package org.westos_01;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * 
 *将UDP编程的发送端和接收端优化!
 */
public class SendDemo {

	public static void main(String[] args) throws IOException {
		//创建发送端的Socket对象
		DatagramSocket  ds = new DatagramSocket() ;
		
		//创建数据报包对象
		byte[] bys = "hello,udp,我来了".getBytes() ;
		//DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
        //构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
		DatagramPacket dp = new DatagramPacket(bys, bys.length,InetAddress.getByName("192.168.0.102"),12345) ;
	
		//发送数据
		ds.send(dp);
		
		//释放资源
		
		ds.close();
	}
}
                接收端:
package org.westos_01;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * DatagramSocket:此类表示用来发送和接收数据报包的套接字。 
 * DatagramPacket:此类表示数据报包。
 *
 */

public class ReceiveDemo {
	
	public static void main(String[] args) throws IOException {
		
		//创建接收端的Socket对象
		//DatagramSocket(int port):创建数据报套接字并将其绑定到本地主机上的指定端口
		DatagramSocket ds = new DatagramSocket(12345) ;
		
		//创建接收容器
		//创建字节数组的大小1024或者1024的倍数
		byte[] bys = new byte[1024] ;
		DatagramPacket dp = new DatagramPacket(bys, bys.length);
		
		//调用接收的方法
		ds.receive(dp);//阻塞式方法
		//java中的阻塞式方法是指在程序调用改方法时,必须等待输入数据可用或者检测到输入结束或者抛出异常,
		//否则程序会一直停留在该语句上,不会执行下面的语句;
		
		//解析数据,将数据展示在控制台
		//获取ip地址
		//getAddress():返回机器的ip地址,返回值类型为:InetAddress
		//getHostAddress():返回机器的ip地址,返回值类型为:String
		String ip = dp.getAddress().getHostAddress() ;
		//public byte[] getData() 获取缓冲区中实际的字节数
		//public int getLength()  获取缓冲区中实际的长度
		String s = new String(dp.getData(), 0,dp.getLength()) ;
		
		//展示控制台
		System.out.println("from"+ip+"data is:"+s);
		
		//释放资源
		ds.close();
	}
}

        完成数据的多次发送和接收:
        举例:

                发送端:
package org.westos_02;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * 需求: 将发送端的数据改变方式,并且多次发送
 * 
 *
 */
public class SendDemo {

	public static void main(String[] args) {

		try {
			//创建Socket对象:数据报套接字是包投递服务的发送或接收点
			DatagramSocket ds = new DatagramSocket();

			//键盘录入
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

			String line = null ; //读了一次
			while((line=br.readLine())!=null){

				//自定义结束条件
				if("886".equals(line)) {
					break ;
				}

				byte[] bys = line.getBytes() ;
				//创建数据报包
				DatagramPacket dp = new DatagramPacket(
						bys,bys.length,InetAddress.getByName("192.168.0.102"), 10086);

				//发送数据
				ds.send(dp);
			
			}
			//释放资源
			ds.close();

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
                接收端:
package org.westos_02;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class ReceiveDemo {
	
	public static void main(String[] args) {
		
		try {
			//创建接收端的Socket对象
			DatagramSocket ds = new DatagramSocket(10086);
			
			while(true) {
				//需要创建接收容器
				byte[] bys = new byte[1024] ;
				DatagramPacket dp = new DatagramPacket(bys, bys.length) ;
				
				//接收
				ds.receive(dp);
				
				//解析数据
				String ip = dp.getAddress().getHostAddress() ;
				String s = new String(dp.getData(), 0, dp.getLength()) ;
				
				System.out.println("from" +ip +"data is:"+s);
				
				//释放资源,接收端不停地接收数据,所以不应该该关闭
				//ds.close();
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
        使用接口的方式完成数据的多次发送接收:
        举例:
                接收端:
package org.westos_03;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class ReceiveThread implements Runnable {

	private DatagramSocket ds;

	public ReceiveThread(DatagramSocket ds) {
		this.ds = ds;
	}

	@Override
	public void run() {
		try {

			while(true) {
				//需要创建接收容器
				byte[] bys = new byte[1024] ;
				DatagramPacket dp = new DatagramPacket(bys, bys.length) ;
				
				//接收
				ds.receive(dp);
				
				//解析数据
				String ip = dp.getAddress().getHostAddress() ;
				String s = new String(dp.getData(), 0, dp.getLength()) ;
				
				System.out.println("from" +ip +"data is:"+s);
				
				//释放资源,接收端不停地接收数据,所以不应该该关闭
				//ds.close();
			}
		}catch(IOException e) {
			e.printStackTrace(); 
		}
	}

}
                发送端:
package org.westos_03;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class SendThread implements Runnable {

	private DatagramSocket ds ;
	public SendThread(DatagramSocket ds) {
		this.ds = ds ;
	}
	
	@Override
	public void run() {
		try {
			//使用字符缓冲输入流
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
			String line = null ;
			//不断发送数据
			while((line=br.readLine())!=null) {
				//自定义结束条件
				if("over".equals(line)) {
					break ;
				}
				
				byte[] bys = line.getBytes() ;
				//创建数据报包
				DatagramPacket dp = 
						new DatagramPacket(bys, bys.length, 
									InetAddress.getByName("192.168.0.102"), 10086) ;
				
				//发送数据
				ds.send(dp);
				
			}
			//释放
			ds.close();
			
		}catch(IOException e) {
			e.printStackTrace(); 
		}
	}

}
                测试端:
package org.westos_03;

import java.net.DatagramSocket;

/**
 ** 多线程:
 * 		Runable接口的方式
 * 		SendThread implements Runnable{
 *              }
 * 		发送端的线程
 * 		接收端的线程
 * 
 * 		主线程
 * 			只需要需一个窗口 ,让我们不断发送数据
 * 
 */
public class ChartRoom {
	
	public static void main(String[] args) throws Exception {
		
		//分别创建发送端和接收端的Socket对象
		DatagramSocket sendSocket = new DatagramSocket() ;
		DatagramSocket receiveSocket = new DatagramSocket(10086) ;
		
		//创建资源对象
		SendThread st = new SendThread(sendSocket) ;
		ReceiveThread rt = new ReceiveThread(receiveSocket) ;
		
		//创建线程对象
		Thread t1 = new Thread(st) ;
		Thread t2 = new Thread(rt) ; 
		
		//启动线程
		t1.start();
		t2.start();
		
	}
}

TCP编程:(建立连接通道);

        特点:
                1> 需要建立连接通道;
2> 数据大小无限制;
3> 可靠连接;

4> 执行效率低;

        举例:
                服务器端:

package org.westos_04;

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 
 *服务端的开发步骤:
 *	1)创建服务器端的Socket对象
 *	2)监听客户端的连接(阻塞方法)
 *	3)获取通道内的输入流
 *	4)读取数据,显示控制台
 *	5)释放资源
 *
 *ava.net.BindException: Address already in use: JVM_Bind  地址被绑定,因为已经有服务器在监听客户端连接
 */
public class ServerDemo {
	
	public static void main(String[] args) throws Exception {
		
		//1)创建服务器端的Socket对象
		//public ServerSocket(int port) throws IOException创建绑定到特定端口的服务器套接字
		ServerSocket ss = new ServerSocket(12306) ;
		
		//2)监听客户端的连接(阻塞方法)
		//public Socket accept():   throws IOException侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞
		Socket s = ss.accept() ;
		
	 	//3)获取通道内的输入流
		//InputStream getInputStream() 
		InputStream in = s.getInputStream() ;
		
	 	//4)读取数据,显示控制台
		//获取ip文本形式
		//public InetAddress getInetAddress()
		String ip = s.getInetAddress().getHostAddress() ;
		byte[] bys = new byte[1024] ;
		int len = in.read(bys) ;
		String data = new String(bys, 0, len) ;
		System.out.println("from" +ip +"data is :"+data);
		
	 	//5)释放资源
		s.close();
		//ss.close(); 服务端可以不关闭
		
	}
}
                客户端:
package org.westos_04;

import java.io.OutputStream;
import java.net.Socket;

/**
 *TCP(建立连接通道)编程的客户端的开发步骤
 *		1)创建客户端的Socket对象
 *			Socket:就是客户端的Socket
 *				构造方法
 *					public Socket(InetAddress address, int port)
 *					public Socket(String host, int port):创建客户端套接字对象,并且指定端口号和ip文本形式
 *		2)获取通道内的输出流对象
 *		3)给服务器端写数据 
 *		4)释放资源
 *	
 *	java.net.ConnectException: Connection refused: connect 连接被拒绝
 *
 *	不要先运行客户端,客户端的连接需要服务器监听到才能连接
 */
public class ClientDemo {

	public static void main(String[] args) throws Exception {
		//1)创建客户端的Socket对象
		//public Socket(String host, int port)
		Socket s = new Socket("192.168.10.1", 12306) ;
		
		//2)获取通道内的输出流对象
		//public OutputStream getOutputStream():获取套接字 的输出流
		OutputStream out = s.getOutputStream() ;
		
		//3)给服务器端写数据 过去
		out.write("hello,Tcp,我来了".getBytes());
		
		//释放资源
		s.close();
	}
}
        

猜你喜欢

转载自blog.csdn.net/Future_LL/article/details/80580276