黑马程序员-网络编程概述-网络模型-UDP-TCP

---------------------- android培训、java培训、期待与您交流! ---------------------- 
网络编程(概述)
网络模型
  • OSI参考模型
  • TCP/IP参考模型
网络通讯要素
  • IP地址
  • 端口号
  • 传输协议
实现通讯的步骤
  1. 通过IP地址找到对方
  2. 通过指定的端口号连接到应用程序,实现数据传输。(为了将数据发送到指定的程序上,用来标识应用程序的的数字,为了方便称呼这些数字,命名它们为端口。这些端口是虚拟的,所以是逻辑端口。)
  3. 定义通讯规则,这个通讯规则称为协议。国际组织定义了通用协议Tcp/IP
网络模型
网络通讯要素
IP地址:
  • 网络中设备的标识
  • 不易记忆,可用主机名
  • 本地回环地址:127.0.0.1 主机名:localhost
端口号
  • 用于标识进程的逻辑地址,不同进程的标识
  • 有效端口:0-65535,其中0-1024系统使用或保留端口
传输协议
  • 通讯的规则
  • 常见的协议:TCP,UDP
UDP
  • 将数据源和目的封装成数据包中,不需要建立连接
  • 每个数据报的大小限制在64k内
  • 因为无连接,是不可靠协议
  • 不需要建立连接,速度快
TCP
  • 建立连接,形成传输数据的通道。
  • 在连接中进行大数据量传输。
  • 通过三次握手完成连接,是可靠协议。
  • 必须建立连接。效率会稍低。
Socket
  • Socket就是为网络服务提供的一种机制。
  • 通信的两端都有Socket。
  • 网络通信其实就是Socket间的通信。
  • 数据在两个Socket间通过IO传输。
UDP发送
public class DatagramSocket
extends Object
此类表示用来发送和接收数据报包的套接字。
数据报套接字是包投递服务的发送或接收点。每个在数据报套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。
在 DatagramSocket 上总是启用 UDP 广播发送。为了接收广播包,应该将 DatagramSocket 绑定到通配符地址。在某些实现中,将 DatagramSocket 绑定到一个更加具体的地址时广播包也可以被接收。
练习代码:
/*
 * 需求:通过UDP传输方式,将一段文字数据发送出去。
 * 思路:
 * 1,建立UdpSocket服务。
 * 2,提供数据,并将数据封装到数据包中。
 * 3,通过Socket服务的发送功能,将数据包发出去。
 * 4,关闭资源。
 */
public class DataGramSocketSendDemo {

	public static void main(String[] args) {
		//创建udp socket,建立端点
		DatagramSocket ds = null;
		//定义数据包,用于接收数据。
		byte[] value = "hello this is test data".getBytes();
		try {
			DatagramPacket dap = new DatagramPacket(value,value.length,InetAddress.getByName("192.168.1.110"),6666);
			ds = new DatagramSocket();
			ds.send(dap);
		} catch (Exception e) {
			throw new RuntimeException("udp数据发送异常");
		}finally{
			ds.close();
		}
	}
}

接收端:

/*
 * 需求:
 * 定义一应用程序,用于接收UDP协议传输的数据并处理。
 * 定义UDP的接收端。
 * 思路:
 * 1,定义UDPSocket服务,通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。方便于明确哪些数据
 * 		来过该应用程序可以处理。
 * 2,定义一个数据包,因为要存储接收到字节数据。
 * 		因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
 * 3,通过Socket服务的Receive方法将收到的数据存入已定义好的数据包中。
 * 4,通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。
 * 5,关闭资源。
 */
public class DatagramSocketReceDemo {

	public static void main(String[] args) {
		DatagramSocket das = null;
			try {
				das = new DatagramSocket(6666);
				while(true){
				byte[] value = new byte[1024];
				DatagramPacket dap = new DatagramPacket(value,value.length);
				 das.receive(dap);
				 String str = new String(dap.getData(),0,dap.getLength());
				 int port = dap.getPort();
				 String ip = new String(dap.getAddress().getHostAddress());
				 System.out.println(str + "::" + ip + "::" + port);
			}
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
}

UDP聊天:
public class UdpChat {

	public static void main(String[] args) {
		try {
			DatagramSocket send = new DatagramSocket();
			DatagramSocket rece = new DatagramSocket(10002);
			new Thread(new SendClient(send)).start();
			new Thread(new ReceClient(rece)).start();
		} catch (Exception e) {
			throw new RuntimeException("接口创建失败");
		}
	}
}
class ReceClient implements Runnable{
	DatagramSocket das;
	public ReceClient(DatagramSocket das){
		this.das = das;
	}
	@Override
	public void run() {
		try {
			byte[] value = new byte[1024];
			DatagramPacket dap = new DatagramPacket(value, value.length);
			while(true){
				das.receive(dap);
				String ip = dap.getAddress().getHostAddress();
				String data = new String(dap.getData(),0,dap.getLength());
				System.out.println(ip + "::" + data);
			}
			
		} catch (Exception e) {
			throw new RuntimeException("接收端异常");
		}
		
	}
}

class SendClient implements Runnable{
	DatagramSocket das;
	public SendClient(DatagramSocket das){
		this.das = das;
	}
	@Override
	public void run() {
		try {
			byte[] value = new byte[1024];
			BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
			String len = null;
			while((len = buf.readLine()) != null){
				if(len.equals("over")){
					break;
				}
				value = len.getBytes();
				//如果想群聊可以把ip地址换成广播地址,接收端地址使用同样的接收端口
				DatagramPacket dap = new DatagramPacket(value, value.length,InetAddress.getByName("192.168.1.106"),10002);
				das.send(dap);
			}
		} catch (Exception e) {
			throw new RuntimeException("发送端异常");
		}
		
	}
	
}


TCP传输
  1. Socket和ServerSocket
  2. 建立客户端和服务器端
  3. 建立连接后,通过Socket中的IO流进行数据的传输
  4. 关闭Socket
  5. 同样,客户端与服务器端是两个独立的应用程序
练习代码:
/**
 * 需求:给服务端发送一个文本数据
 * 步骤:
 * 1.创建Socket服务,并指定要连接的主机和端口
 * @author onlin_000
 *
 */
public class TcpSend {

	public static void main(String[] args) {
		try {
			//创建客户端的socket服务。指定目的主机和端口
			Socket s = new Socket(InetAddress.getByName("192.168.1.106"),10003);
			//为了发送数据,应该获取socket流中的输出流。
			OutputStream os = s.getOutputStream();
			os.write("Hello this is test data!".getBytes());
			s.close();
		} catch (IOException e) {
			throw new RuntimeException("客户端异常");
		}
	}
}
TCP服务端:
/**
 * 需求:定义端点接收数据并打印在控制台上。
 * 服务端:
 * 1.建立服务端的socket服务。ServerSocket(); 并监听一个端口
 * 2.获取连接过来的客户端对象。通过ServerSocket的accept方法。没有连接就会等,所以这个方法是阻塞式的	
 * 3.客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流,来读取发过来的数据,并打印在控制台上。
 * 4.关闭(可选)
 * @author onlin_000
 *
 */
public class TcpServer {

	public static void main(String[] args) {
		ServerSocket ss = null;
		try {
			ss = new ServerSocket(10003);
			Socket s = ss.accept();
			InputStream ins = s.getInputStream();
			byte[] data = new byte[1024];
			int len = ins.read(data);
			System.out.println(new String(data,0,len));
			//关闭客户端连接
			s.close();
		} catch (Exception e) {
			throw new RuntimeException("服务端异常");
			}finally{
				if(ss != null){
					try {
						ss.close();
					} catch (IOException e1) {
						throw new RuntimeException("服务器关闭失败");
					}
				}
		}
	}
}

练习2:
/**
 * 客户端通过键盘录入用户名。
 * 服务端对这个用户名进行校验。
 * 
 * 如果该用户名存在,在服务器端显示xxx已登录。
 * 并在客户端显示xxx欢迎光临。
 * 
 * 如果该用户不存在,正在服务器端显示xxx尝试登录。
 * 并在客户端显示xxx用户不存在
 * @author onlin_000
 *
 */
public class TcpLoadServer {

	public static void main(String[] args) {
		ServerSocket ss = null;
		try {
			ss = new ServerSocket(10006);
			while(true){
				Socket s = ss.accept();
				new Thread(new LoadServer(s)).start();
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}
class LoadServer implements Runnable{
	Socket s;
	LoadServer( Socket s){
		this.s = s;
	}
	@Override
	public void run() {
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip + "..............connected");
		BufferedReader bufin = null;
		try {
			bufin = new BufferedReader(new FileReader(new File("User.txt")));
			BufferedReader buf = 
					new BufferedReader(new InputStreamReader(s.getInputStream()));
			PrintWriter pw = 
					new PrintWriter(s.getOutputStream(),true);
			for(int i = 0; i < 3; i++){
				boolean flag = false;
				String name = buf.readLine();
				if(name == null)
					return;
				String data = null;
				while((data = bufin.readLine()) != null){
					if(name.equals(data))
						flag = true;
				}
				if(flag){
					System.out.println(name + "登录成功");
					pw.println("欢迎" + name + "登录成功");
				}else{
					System.out.println(name + "尝试登录");
				}
			}
			buf.close();
			pw.close();
			bufin.close();
		} catch (Exception e) {
			throw new RuntimeException(ip + "登录失败");
		}
	}
	
}
发送端:
public class TcpLoadClient {

	public static void main(String[] args) {
		BufferedReader bufin = null;
		try {
			bufin = new BufferedReader( new InputStreamReader(System.in));
			Socket s = new Socket(InetAddress.getByName("192.168.1.111"),10006);
			BufferedReader buf = 
					new BufferedReader(new InputStreamReader(s.getInputStream()));
			PrintWriter pw =
					new PrintWriter(s.getOutputStream(),true);
			String name = null;
			while((name = bufin.readLine())!= null){
				
				if(name.equals("over"))
					return;
				pw.println(name);
				String re = buf.readLine();
				if(re.contains("欢迎"))
					System.out.println(re);
				pw.close();
				buf.close();
				s.close();
			}
		} catch (Exception e) {
			throw new RuntimeException("客户端异常");
		}
	}
}
Tcp练习3:
/**
 * 让多个客户端用户能够同时并发上传文件
 * 那么服务端最好就将每个客户端封装到一个单独的线程中,这样就可以同时处理对个客户端的请求。
 * 
 *如何定义线程呢?
 *只要明确了每一个客户端要在服务端执行的代码。
 * @author onlin_000
 *
 */
public class TcpUploadingByThreadServer {

	public static void main(String[] args) {
		while(true){
			ServerSocket ss = null;
			try {
				ss = new ServerSocket(10006);
				Socket s = ss.accept();
				new Thread(new clientByThread(s)).start();
			} catch (IOException e) {
				throw new RuntimeException("服务器启动失败!");
			}finally{
				try {
					ss.close();
				} catch (IOException e) {
					throw new RuntimeException("服务器关闭失败!");
				}
			}
		}
		
	}
}
class clientByThread implements Runnable{

	Socket s;
	clientByThread(Socket s){
		this.s = s;
	}
	@Override
	public void run() {
		String ip = s.getInetAddress().getHostAddress();
		int count = 0;
		try {
			File file = new File("server\\"+ ip + "(" + count + ")"+".bmp");
			while(file.exists()){
				file = new File("server\\"+ ip + "(" + (++count) + ")"+".bmp");
			}
			FileOutputStream fos = new FileOutputStream(file);
			InputStream ins = s.getInputStream();
			byte[] data = new byte[1024];
			int len = 0;
			while((len = ins.read(data)) != -1){
				fos.write(data,  0, len);
			}
			OutputStream outs = s.getOutputStream();
			outs.write("上传成功!".getBytes());
			fos.close();
			ins.close();
			outs.close();
			s.close();
		} catch (Exception e) {
			throw new RuntimeException(ip +"上传失败!");
		}
	}
客户端:
public class TcpUploadingByThreadClient {

	public static void main(String[] args) {
		try {
			Scanner sc = new Scanner(System.in);
			System.out.println("请输入图片路径,请用\\\\代替\\");
			String path = sc.nextLine();
			sc.close();
			File file = new File(path);
			if(!file.exists()){
				System.out.println("请输入正确的路径");
				return;
			}
			if(!file.getName().endsWith(".bmp")||file.getName().endsWith(".BMP")){
				System.out.println("请选择正确的文件");
				return;
			}
			if(file.length()>1024*1024*5){
				System.out.println("文件太大!");
				return;
			}
			Socket s = new Socket(InetAddress.getByName("192.168.1.111"),10006);
			FileInputStream fis = new FileInputStream(file);
			OutputStream ous = s.getOutputStream();
			byte[] buf =new byte[1024];
			int len = 0;
			while((len = fis.read(buf)) != -1){
				ous.write(buf, 0, len);
			}
			s.shutdownOutput();
			InputStream ins = s.getInputStream();
			int i =ins.read(buf);
			System.out.println(new String(buf,0,i));
			ous.close();
			fis.close();
			s.close();
			ins.close();
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}

练习3:
TCP上传图片
public class TcpUploadingPiceServer {

	public static void main(String[] args) throws Exception {
		ServerSocket ss = new ServerSocket(10005);
		Socket s = ss.accept();
		FileOutputStream fos = new FileOutputStream(new File("Server.bmp"));
		InputStream ins = s.getInputStream();
		byte[] data = new byte[1024];
		int len = 0;
		while((len = ins.read(data)) != -1){
			fos.write(data,  0, len);
		}
		OutputStream outs = s.getOutputStream();
		outs.write("上传成功!".getBytes());
		fos.close();
		ins.close();
		outs.close();
		s.close();
		ss.close();
		
	}
}
TCP客户端:

/**
 * 上传图片
 * 客户端
 * 1.服务端点
 * 2.读取客户端已有的图片数据。
 * 3.通过socket输出流将数据发给服务端。
 * 4.读取服务端反馈信息。
 * 5.关闭。
 * @author onlin_000
 *
 */
public class TcpUploadingPiceClient {

	public static void main(String[] args) throws Exception {
		Socket s = new Socket(InetAddress.getByName("192.168.1.111"),10005);
		FileInputStream fis = new FileInputStream(new File("test.bmp"));
		OutputStream ous = s.getOutputStream();
		byte[] buf =new byte[1024];
		int len = 0;
		while((len = fis.read(buf)) != -1){
			ous.write(buf, 0, len);
		}
		s.shutdownOutput();
		InputStream ins = s.getInputStream();
		int i =ins.read(buf);
		System.out.println(new String(buf,0,i));
		ous.close();
		fis.close();
		s.close();
		ins.close();
	}
}
TCP练习4:
/**
 * 需求:建立一个文本转换服务器。
 * 客户端给服务端发送文本,服务端会将文本转换成大写载返回给客户端。
 * 而且客户端可以不断的进行文本转换。当客户端输入over时,转换结束	
 * 分析:
 * 客户端:既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。
 * 源:键盘录入。
 * 目的:网络设备,网络输出流。
 * 而且操作的是文本数据,可以选择字符流。
 * 步骤:
 * 1.建立服务。
 * 2.获取键盘录入。
 * 3.将数据发给服务端。
 * 4.获取服务端返回的大写数据。
 * 5.结束,关闭资源。
 * 
 * 改例出现的问题。
 * 现象:客户端和服务端都在莫名的等待。
 * 原因:客户端和服务端都有阻塞式的方法。这些方法没有读到结束标记,那么就一直等待,而导致两端都在等待。
 * 现象:第一次能正常运行,第二次报错
 * 原因:使用过的端口没有被释放,第二次再次使用此端口会报错。
 * @author onlin_000
 *
 */
public class TransServer {

	public static void main(String[] args) {
		new Thread(new Server()).start();
		new Thread(new Sender()).start();
	}
}
class Sender implements Runnable{
	
	@Override
	public void run() {
		Socket s = null;
		try {
			s = new Socket(InetAddress.getByName("192.168.1.106"),10008);
			//读取客户端输入的数据
			BufferedReader bufin = 
					new BufferedReader(new InputStreamReader(System.in));
			//用于向流中写入数据
			BufferedWriter buw = 
					new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
			//用于读取服务器返回的大写数据
			BufferedReader buf = 
					new BufferedReader(new InputStreamReader(s.getInputStream()));
			String len = null;
			System.out.println("请输入");
			while((len = bufin.readLine()) != null){
				if(len.equals("over")){
					break;
				}
				buw.write(len);
				buw.newLine();
				buw.flush();
				System.out.println(buf.readLine());
			}
		} catch (Exception e) {
			throw new RuntimeException("发送端异常");
		}finally{
			if(s != null){
				try {
					s.close();
				} catch (IOException e) {
					throw new RuntimeException("客户端流关闭异常");
				}
			}
		}
	}
}
class Server implements Runnable{

	@Override
	public void run() {
		ServerSocket ss = null;
		try {
			ss = new ServerSocket(10008);
			Socket s = ss.accept();
			//读取客户端发来的数据
			BufferedReader bur = 
					new BufferedReader(new InputStreamReader(s.getInputStream()));
			//写入处理后的数据
			BufferedWriter buw =
					new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
			String len = null;
			while((len = bur.readLine()) != null){
				buw.write(len.toUpperCase());
				buw.newLine();
				buw.flush();
			}
			s.close();
			ss.close();
		} catch (Exception e) {
			throw new RuntimeException("服务端异常");
		}
	}
	
}
浏览器客户端-自定义服务端(severdemo.java) 
public class ServerDemo {

	public static void main(String[] args) {
		ServerSocket ss;
		try {
			ss = new ServerSocket(10010);
			Socket s = ss.accept();
			System.out.println(s.getInetAddress().getHostAddress() + "...............connected");
			PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
			pw.println("Hello celient!");
			ss.close();
			s.close();
		} catch (IOException e) {
			throw new RuntimeException("服务端创建失败");
		}
	}
}


黑马程序员-网络编程概述-网络模型-UDP-TCP_第1张图片
自定义浏览器-Tomcat服务器

---------------------- android培训、java培训、期待与您交流! ---------------------- 

你可能感兴趣的:(java,黑马程序员)