网络编程一:概述、网络模型、TCP\UDP、Socket套接字、UDP发送和接收、UDP聊、阻塞式方法

本文介绍了网络编程的基础知识,包括网络模型、IP地址、TCP与UDP的特点以及Socket套接字的使用。详细讲解了InetAddress类、DatagramSocket类和DatagramPacket类在UDP发送和接收中的应用,提供了UDP发送端和接收端的实例,并展示了如何实现简单的UDP聊天程序。
摘要由CSDN通过智能技术生成

1  网络编程概述

网络编程就是通过使用套接字(Socket来达到进程间通信目的的编程,在两个设备之间进行数据交换。

在网络中的连接,是基于请求/响应的方式,就是发起连接请求的程序(Client客户端),发送连接请求到接收请求的程序(Server服务端),客户端可以在需要时才启动,而服务端需要一直运行,一直侦听请求。

 

网络模型:

      OSI七层模型从下往上:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。

      TCP/IP四层模型从下往上:网络接入层(主机-网络)、网际互联层、传输层、应用层。

   常用概念:

   IP地址:IP地址是网络中设备的标识,是一台主机在网络中的地址。127.0.0.1是本地回环地址。

端口号:数据要发送到对方主机上指定的应用程序上,为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识。为了方便称呼这个数字,叫做端口(逻辑端口),是不同进程的标识。

有效端口:0~65535,其中0~1024系统使用或保留端口。

传输协议:我们定义了网络中的通信规则,这个通信规则称为协议。国际组织定义了通用协议TCP/IP。 

 

TCP/IP模型中,

应用层协议有HTTPFTP协议,

传输层有TCPUDP协议,

网际层有IP协议,

网络接入层有ARP协议。


2  IP地址InetAddress

java.net包中的InetAddress类:此类表示互联网协议 (IP) 地址。

 

InetAddress类中常用方法:

getLocalHost():静态方法,获取本地主机的IP地址对象,返回InetAddress类型。

getByName():静态方法,根据一个主机名或IP地址,返回一个InetAddress对象。

getAllByName():静态方法,根据一个主机名,返回其IP地址组成的数组,InetAddress[]

getHostAddress():获取InetAddress对象的主机IP地址,返回字符串类型。

getHostName():获取InetAddress对象的主机名,返回字符串类型。

代码演示:

import java.net.*;

class IPDemo {
	public static void main(String[] args) throws Exception {
		//获取一个InetAddress对象
		InetAddress i = InetAddress.getLocalHost(); //获取本地主机的IP地址对象。
		
		System.out.println(i.toString());
		System.out.println("address: "+i.getHostAddress());//返回主机IP地址
		System.out.println("name: "+i.getHostName());//返回主机名
		
		//根据IP或主机名,获取一个InetAddress对象
		InetAddress ia = InetAddress.getByName("192.168.0.103"); 
		System.out.println("罗琦HostAddress: "+ia.getHostAddress());
		System.out.println("罗琦HostName: "+ia.getHostName());
		
		//根据IP或主机名,获取一个InetAddress对象。
		InetAddress[] ib = InetAddress.getAllByName("www.baidu.com");
		for(InetAddress ibb : ib){
			System.out.println("百度HostAddress: "+ibb.getHostAddress());
			System.out.println("百度HostName: "+ia.getHostName());
		}
	}
}

3  TCPUDPSocket(套接字)

TCPUDP是两种不同的传输层协议,TCP即传输控制协议,UDP即用户数据报协议。

 

TCP特点:

1,建立连接,形成传输数据的通道。

2,在连接中进行大数据量传输。

3,通过三次握手完成连接,是可靠协议。

4,必须建立连接,效率会稍低。

 

UDP特点:

1,将数据及源和目的封装成数据包中,不需要建立连接。

2,每个数据报的大小在限制在64k内。

3,因无连接,是不可靠协议。

4,不需要建立连接,速度快。

 

Socket即套接字,是进程间通信的机制,网络上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket英文原意为插座,在Socket通信机制中,一台主机就像一个插座,每个服务对应的端口就是一个插孔,连接到不同的端口,就对应不同的服务。

Socket特点:

1Socket就是为网络服务提供的一种机制。

2,通信的两端都有Socket

3,网络通信其实就是Socket间的通信。

4,数据在两个Socket间通过IO传输。

 

4  UDP发送端实例——DatagramSocket类、DatagramPacket

定义一个UDP协议的发送端。

需求:通过UDP传输方式,将一段文字数据发送出去。

思路:

1,建立UDPsocket服务。

2,提供数据,并将数据封装到数据包中。

3,通过socket服务的发送功能,将数据包发出去。

4,关闭资源。

 

DatagramSocket类,是UDP协议中用于发送和接收数据包的套接字。Java.net包中。

DatagramSocket( int)构造方法,创建一个Socket并绑定到本地主机的指定端口。

发送时,通过构造函数指定要发送到的端口。

接收时,通过构造函数指定要接收哪个端口上的数据包。

send( dp)方法:从这个Socket发送数据包。

receive( dp)方法:从这个Socket接收数据包,阻塞式方法。

 

DatagramPacket类,表示数据包。Java.net包中的。

getAddress()DatagramPacket类的getAddress方法返回数据包中IP地址,InetAddress对象。

getData():获取数据包中的数据,返回字节数组。

getLength():返回数据包中数据的长度,字节数组长度。

getPort():返回端口号,数据包发送到这个端口,或从这个端口发出。

 

代码示例:

import java.net.*;

class UdpSend {   //创建服务、IP地址均会出现异常,send()有IO异常
	public static void main(String[] args) throws Exception{
		
		//1,创建udp的socket服务。通过DatagramSocket对象。
		DatagramSocket ds = new DatagramSocket(); //套接字绑定到本地任意可用端口。
		
		//2,确定数据,并封装成数据包。
		//DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
		byte[] buf = "udp ge men lai la".getBytes();
		DatagramPacket dp = 
			new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10000);
		
		//3,通过socket服务,将已有的数据包发送出去,通过send方法。
		ds.send(dp);
		
		//4,关闭资源。
		ds.close();
	}
}

5  UDP接收端实例、阻塞式方法

定义一个UDP协议的接收端。

需求:定义一个应用程序,用于接收UDP协议传输的数据并处理的。

思路:

1,创建UDPSocket对象。通常会监听一个端口,其实就是给这个接收应用程序,定义一个数字标识(端口)。方便于明确哪些数据过来该应用程序可以处理。

2,创建一个数据包,因为要存储接收到的字节数据。因为数据包对象中有更多功能,可以提取字节数据中的不同数据信息。

3,通过Socket对象的receive方法,将收到的数据存入已定义好的数据包中。

4,通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上。

5,关闭资源。

 

DatagramSocketreceive( dp)是阻塞式方法。

阻塞式方法:程序一直停在这里等,直到接收到数据才继续执行。IO流中的输入流的read方法也是阻塞式方法。

 

代码示例:

import java.net.*;

class UdpReceive{
	public static void main(String[] args) throws Exception{
		//1,创建udp的socket服务,指定端口。
		DatagramSocket ds = new DatagramSocket(10000);//监听10000端口,如果不指定,端口随机分配
		
		//2,定义数据包,用于存储接收到的数据。
		byte[] buf = new byte[1024];
		DatagramPacket dp = new DatagramPacket(buf,buf.length);//数据包存储buf字节数组
		
		//3,通过服务的receive方法,将收到的数据存入数据包中。
		ds.receive(dp); //阻塞式方法:程序一直停在这里等,接收到数据才继续执行。
		
		//4,通过数据包的方法,获取其中的数据。(IP地址、端口、数据)
		String ip = dp.getAddress().getHostAddress();//getAddress()返回主机的InetAddress对象(即IP地址)
		                                           //getHostAddress()返回InetAddress对象的主机ip 
		String data = new String(dp.getData(),0,dp.getLength());//得到数据包中封装的数据。
		
		int port = dp.getPort();  //得到端口。
		System.out.println(ip+"::"+data+"::"+port);  //打印出来
		
		//5,关闭资源。
		ds.close();
	}
}

6  完整的UDP传输实例(键盘录入方式)

使用键盘录入的方式,实现UDP数据传输。

发送端通过键盘,每录入一些数据,接收端就接收一些数据。再发送,再接收。

两个包含主函数的类在一个java文件中,先统一编译,再分别执行。

即:javac UdpDemo2.java

java UdpSend2

java UdpReceive2

 

代码示例:

import java.net.*; //用到net包往往会用到io包,网络传输用到IO流 
import java.io.*;

class UdpSend2 {
	public static void main(String[] args) throws Exception{
		DatagramSocket ds = new DatagramSocket(); //创建Socket服务 
		
		BufferedReader bufr = 
			new BufferedReader(new InputStreamReader(System.in));//读取键盘录入
			
		String line = null;
		while((line=bufr.readLine())!=null){ //readLine阻塞式方法
			if(line.equals("886"))
				break;
			byte[] buf = line.getBytes();
			
			//创建一个发送的数据包,其中定义了数据、数据长度、目的ip、目的端口。
			DatagramPacket dp = 
				new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10001);//本机IP
			
			ds.send(dp); //Socket服务把数据包dp发送出去,udp传输。
		}
		ds.close(); //关闭Socket资源。
	}
}

class UdpReceive2 {
	public static void main(String[] args) throws Exception{
		DatagramSocket ds = new DatagramSocket(10001);//绑定10001端口
		
		while(true){
			byte[] buf = new byte[1024*64]; //数据包最大64KB
			
			//创建一个存储接收数据的数据包,定义了数据、数据长度。
			DatagramPacket dp = new DatagramPacket(buf,buf.length);
			
			ds.receive(dp);  //阻塞式方法,Socket接收数据并存入dp数据包中。
			
			String ip = dp.getAddress().getHostAddress(); //获取IP地址
			String data = new String(dp.getData(),0,dp.getLength());
			
			System.out.println(ip+"::"+data);
		}
		//没有关闭资源,演示阻塞式方法。
	}
}

7  UDP聊天程序

需求:编写一个聊天程序,这一个程序中有接收数据的部分,也有发送数据的部分。这两部分需要同时执行,需要用多线程技术。

思路:

1,需要用到多线程技术。一个线程控制收,一个线程控制发。

2,因为收和发动作是不一致的,所以要定义两个run方法。

3,而且这两个方法要封装到不同的类中。

 

为了方便演示阻塞式方法,此例中没有关闭资源DatagramSocket

代码示例:

import java.net.*;
import java.io.*;

class Send implements Runnable {//实现Runnable接口,多线程的方式之一。
	private DatagramSocket ds;
	public Send(DatagramSocket ds){
		this.ds = ds;
	}
	public void run(){
		try{
			BufferedReader bufr = 
				new BufferedReader(new InputStreamReader(System.in)); //读取键盘录入 
			
			String line = null;
			while((line=bufr.readLine())!=null){ //readLine()阻塞式方法 
				if(line.equals("886"))
					break;
				byte[] buf = line.getBytes();
				
				//创建一个发送的数据包,其中定义了数据、数据长度、目的ip、目的端口。
				DatagramPacket dp = 
					new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10002);
					
				ds.send(dp); //Socket服务把数据包dp发送出去,udp传输方式。
			}
		}
		catch(Exception e){
			throw new RuntimeException("发送端失败");
		}
	}
}

class Receive implements Runnable{
	private DatagramSocket ds;
	public Receive(DatagramSocket ds){
		this.ds = ds;
	}
	public void run(){
		try{
			while(true){
				byte[] buf = new byte[1024*64];
				DatagramPacket dp = new DatagramPacket(buf,buf.length);//创建一个存储接收数据的数据包 
				
				ds.receive(dp); //阻塞式方法,Socket接收数据并存入dp数据包中。
				
				String ip = dp.getAddress().getHostAddress();
				String data = new String(dp.getData(),0,dp.getLength());
				
				System.out.println(ip+"::"+data);
			}
		}
		catch(Exception e){
			throw new RuntimeException("接收端失败");
		}
	}
}

class ChatDemo{
	public static void main(String[] args) throws Exception{//抛出监听端口时的Socket异常 
		DatagramSocket sendSocket = new DatagramSocket();
		DatagramSocket receSocket = new DatagramSocket(10002);
		
		new Thread(new Send(sendSocket)).start(); //启动线程 
		new Thread(new Receive(receSocket)).start();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值