网络编程总结

一、网络编程三个要素
1.IP地址:网络中设备(计算机)的唯一标识
Ipv4: 占4个字节,点分十进制表示法. 举例: 192.168.91.126
Ipv6: 占16个字节,冒分十六进制表示法,举例:fe80::4d1:d7cb:3ba7:490b%10
2.端口号:计算机中应用程序的唯一标识, 范围[0~65535]
3.通信协议:
UDP: 面向无连接、不可靠的协议、一个数据包大小在64KB以内
TCP: 面向有连接、可靠的协议,数据大小没有限制
二、UDP通信代码编写
1.发送端

1.发送端
		//1)创建DatagramSocket对象
		DatagramSocket socket = new DatagramSocket(); //会绑定一个默认的端口号,系统分配的
		
		//2.创建一个DatagramPacket数据包,数据包装中需要封装数据、数据的长度,对方的ip,对方的贷款好
		DatagramPacket packet = new DatagramPacket(
			字节数组,
			数组的长度,
			对方的ip
			对方的端口号
		);
	
	
		//3.发送数据包
		socket.send(packet);
		
		//4.关闭socket
		socket.close();

2.接收端

//1)创建DatagramSocket对象
		DatagramSocket socket = new DatagramSocket(接收端的端口号); //会绑定一个默认的端口号,系统分配的
		
		//2.创建一个DatagramPacket空数据包
		DatagramPacket packet = new DatagramPacket(
			字节数组,
			数组的长度
		);
	
	
		//3.接收数据包
		socket.receive(packet);
		
		//4.解析数据包(拆包)
		byte[] data = packet.getData();
		int length = packet.getLength();
		//如果发送的数据是一个字符串,可以把data数组中有效的数据转换为字符串
		String str = new String(data,0,length);
		
		//5.关闭socket
		socket.close();

三、TCP通信
1.客户端(Socket)


		//1)创建Socket对象,指定服务端的ip地址和端口号
		Socket socket = new Socket(服务端的ip地址, 服务端口号);
	
		//2)通过socket可以获取一个输出流,用于往服务端发送数据
		OutputStream os = socket.getOutputStream();
		os.write(字节数据);
		
		//3)读取服务端返回的数据
		InputStream is = socket.getInputStream();
		byte[] bytes = new byte[1924];
		int len;
		while(len = is.read(bytes)){
			String str = new String(data,0,len);
			System.out.println(str);
		}
		
		//4)释放资源
		socket.close();

2.服务端(ServerSocket)

//1)创建一个ServerSocket对象,注册一个服务端的端口
		ServerSocket server = new ServerSocket(服务端口号);
		
		//2)监听客户端
		Socket socket = server.accept(); //接收客户端
		
		//3)获取输入流,读取客户端发过来的消息
		InputStream is = socket.getInputStream();
		byte[] bytes = new byte[1924];
		int len;
		while(len = is.read(bytes)!=-1){
			String str = new String(data,0,len);
			System.out.println(str);
		}
		
		//4)获取输出流,往客户端回写数据
		OutputStream os = socket.getOutputStream();
		os.write(字节数据);
		
		//5)释放资源
		socket.close();```
3.在上面的代码上做优化(实现多发多收)
客户端代码:
```java
// 1、创建一个Socket对象,请求与服务器的连接(TCP通信)
			Socket socket = new Socket("127.0.0.1",10011);

			// 2、从socket通信管道中得到一个字节输出流,负责写数据出去
			OutputStream os = socket.getOutputStream();
			//为了让流能够直接输出字符串,把OutputStream转换为Writer
			OutputStreamWriter osw = new OutputStreamWriter(os);
			//为了能够写一行,把OutputStreamWriter封装为BufferedWriter
			BufferedWriter bw = new BufferedWriter(osw);

			// 3、发送消息出去
			Scanner sc =  new Scanner(System.in);
			while (true) {
				System.out.println("请输入你要发的数据:");
				String msg = sc.next();
				if(msg.equals("exit")){
					System.out.println("客户端已经退出");
					break;
				}

				bw.write(msg);
				bw.newLine(); //换行
				bw.flush();  //把数据尽快写到服务端(刷新)
			}

			// 4、释放资源
			socket.close();

服务端代码:

System.out.println("服务端启动。。。");
			// 1、注册端口
			ServerSocket server = new ServerSocket(10011);

			// 2、开始等待接收客户端的socket连接请求
			Socket socket = server.accept();

			// 3、从socket通信管道中得到一个字节输入流读取数据
			InputStream in = socket.getInputStream();
			//为了直接能够直接读取字符数据,把InputStream转换为Reader
			InputStreamReader isr = new InputStreamReader(in);
			//为了能够直接读取一行,在用BufferedReader进行封装
			BufferedReader br = new BufferedReader(isr);

			// 4、读取消息
			//一次读取一行(循环读取)
			String line;
			while ((line = br.readLine())!=null){
				System.out.println(socket.getRemoteSocketAddress()+
						"发来了消息:"+line);
			}

			//释放资源
			socket.close();
	
  1. 在上面的代码上加上多线程改进
    服务端代码:
//第一步:写一个线程任务
			public class ServerRunnable implements Runnable{
				private Socket socket;
//通过ServerRunnable的的有参构造,把把客户端端传进来
				public ServerRunnable(Socket socket) {
					this.socket = socket;
				}

				@Override
				public void run() {
					try {
						//读取客户端Socket发送过来的数据
						InputStream in = socket.getInputStream();
						//把InputStream转换为Reader
						InputStreamReader isr = new InputStreamReader(in);
						//把InputStreamReader再次封装为BufferedRader,就可以一次读取一行了
						BufferedReader br= new BufferedReader(isr);
						String line;
						while ((line = br.readLine())!=null){
							System.out.println(socket.getRemoteSocketAddress()+"发过来的消息:"+line);
						}
					} catch (IOException e) {
						System.out.println(socket.getRemoteSocketAddress()+"...异常下线了");
					}
				}
			}
			
			//第二步:服务端代码
			public class ServerDemo2 {
				public static void main(String[] args) throws Exception {
					System.out.println("服务端启动。。。");
					// 1、注册端口
					ServerSocket server = new ServerSocket(10011);

					while (true) {
						// 2、开始等待接收客户端的socket连接请求
						Socket socket = server.accept();
						System.out.println(socket.getRemoteSocketAddress()+"...上线了");

						//来了一个客户端socket,我就为客户端单独开一条线程来执行任务
						ServerRunnable sr = new ServerRunnable(socket);
						new Thread(sr).start();
					}
				}
			}
			

5.在上面的案例基础上,再次使用线程池改进

public class ServerDemo2 {
			//定义一个线程池
			private static ThreadPoolExecutor pool = new ThreadPoolExecutor(
				5,      //核心线程数
				10,  //最大线程数
				3,      //临时线程空闲的时间
				TimeUnit.SECONDS,  //时间的单位
				new ArrayBlockingQueue<>(10), //任务队列
				Executors.defaultThreadFactory(),   //线程工程(用来造线程的)
				new ThreadPoolExecutor.AbortPolicy()    //拒绝策略(有多余的任务拒绝,并且抛出异常)
			);

			public static void main(String[] args) throws Exception {
				System.out.println("服务端启动。。。");
				// 1、注册端口
				ServerSocket server = new ServerSocket(10011);

				while (true) {
					// 2、开始等待接收客户端的socket连接请求
					Socket socket = server.accept();
					System.out.println(socket.getRemoteSocketAddress()+"...上线了");

					//来了一个客户端socket,我就为客户端单独开一条线程来执行任务
					ServerRunnable sr = new ServerRunnable(socket);
					pool.submit(sr);
				}
			}
		}```
6.在上个案例的基础上,进行消息转发,把消息转发给其他的客户端
修改了线程任务的代码:
```java

			public class ServerRunnable implements Runnable{
				private Socket socket;

				public ServerRunnable(Socket socket) {
					this.socket = socket;
				}

				@Override
				public void run() {
					try {
						//读取客户端Socket发送过来的数据
						InputStream in = socket.getInputStream();
						//把InputStream转换为Reader
						InputStreamReader isr = new InputStreamReader(in);
						//把InputStreamReader再次封装为BufferedRader,就可以一次读取一行了
						BufferedReader br= new BufferedReader(isr);
						String line;
						while ((line = br.readLine())!=null){
							System.out.println(socket.getRemoteSocketAddress()+"发过来的消息:"+line);
							//把消息转发发给其他的客户端
							sendMsgToAllSocket(line);
						}
					} catch (IOException e) {
						System.out.println(socket.getRemoteSocketAddress()+"...异常下线了");
					}
				}

				private void sendMsgToAllSocket(String line) throws IOException {
					//获取所有的客户端对象(Socket对象)
					ArrayList<Socket> list = ServerDemo2.list;
					for (Socket socket1 : list) {
						if(this.socket!=socket1){
							//给其他的客户端回写数据
							OutputStream in = socket1.getOutputStream();
							//把OutputStream转换为Writer
							OutputStreamWriter osw = new OutputStreamWriter(in);
							//为了写一行,再把OutputStreamWriter封装为BufferedWriter
							BufferedWriter bw = new BufferedWriter(osw);
							bw.write(line);
							bw.newLine(); //换行
							bw.flush(); //将数据及时刷新到客户端
						}
					}
				}
			}

修改客户端代码:单独开一条线程用来读取服务端转发的数据

  //为了让客户端在发送数据的同时,也能接收服务端转发过来消息。
		  //需要写一个子线程专门读取服务返回的数据
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						InputStream is = socket.getInputStream();
						InputStreamReader isr =new InputStreamReader(is);
						BufferedReader br = new BufferedReader(isr);

						String line;
						while ((line = br.readLine())!=null){
							System.out.println(socket.getRemoteSocketAddress()+"发来消息:...."+line);
						}
						// 4、释放资源
						socket.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}).start(); 
		
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值