65-网络编程

本文介绍了网络编程的基本概念,包括TCP和UDP两种主要的网络通信方式。详细解析了C/S模型下的Echo服务实现,从单线程到多线程的优化过程,并展示了如何使用Java进行UDP编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网络编程

  网络编程指得是多台主机之间的数据通讯操作。

网络编程简介

  网络的核心定义:两台以上的电脑称为网络,多台电脑之间的通讯。
  网络连接的目的不仅仅是为了进行电脑的串联,更多的情况下是彼此之间的数据通讯,而在通讯的实现上,产生了一系列处理协议:IP、TCP、UDP,所谓的网络编程实现的就是数据通讯操作,只不过这个通讯操作分为客户端与服务器端。
  于是针对于网络程序的开发就有两个模型:

  • C/S(Client/Server、客户端与服务器端):要开发出两套程序,假设服务器端发生改变客户端也应该进行更新处理,这种开发可以由开发者自定义传输协议,并且使用一些私密的端口,安全性较高,但开发维护成本较高。
  • B/S(Browse/Server、浏览器与服务器端):只开发一套服务器程序,利用浏览器作为客户端进行访问,开发维护成本较低(只有一套程序),但是由于其使用公共HTTP协议以及80端口,所以安全性难以保障,现在的开发基本上以“B/S”为主。

  本次学习的网络编程主要为C/S程序模型,分为两种开发:TCP(可靠数据连接)、UDP(不可靠数据连接)。

Echo程序模型

  TCP程序开发时网络程序的最基本的开发模型,其核心特点是使用两个类实现数据交互处理:ServerSocket(服务器端)、Socket(客户端)
6gtLKP.png
  ServerSocket的主要目的是设置服务器的监听端口,而Socket需要指明要连接的服务器地址与端口。
Echo模型
6gNOzR.png

简单Echo程序实现

  1. 实现服务器端
package per.lyz.demo.server;

import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class EchoServer {
	public static void main(String[] args) throws Exception{
		ServerSocket server = new ServerSocket(9999);		//服务器端监听端口
		System.out.println("等待客户端连接。。。。。。");
		Socket client = server.accept();		//有客户端连接
		// 1. 首先需要接受客户端发送的信息,处理之后发送回客户端
		Scanner scan = new Scanner(client.getInputStream());		//客户端输入流
		scan.useDelimiter("\n");		//设置分割符
		PrintStream out = new PrintStream(client.getOutputStream());		//客户端输出流
		boolean flag = true;		//循环标记
		while(flag) {
			if(scan.hasNext()) {		//有数据发送
				String val = scan.next().trim();		//接收发送数据
				if("byebye".equalsIgnoreCase(val)) {
					out.println("See you next time!");
					flag = false;		//结束循环
				} else{
					out.println("[Echo]" + val);
				}
			}
		}
		client.close();
		server.close();
	}
}
  1. 实现客户端程序
package per.lyz.demo.Client;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class EchoClient{
	private static final BufferedReader KEYBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in));
	
	public static void main(String[] args) throws Exception{
		Socket client = new Socket("localhost", 9999);		//定义服务端的连接信息
		// 现在客户端需要有输入输出操作支持,所以依然需要准备出Scanner与PrintWriter
		Scanner scan = new Scanner(client.getInputStream());		//接收服务器端输入内容
		scan.useDelimiter("\n");
		PrintStream out = new PrintStream(client.getOutputStream());		//向服务端发送内容
		boolean flag = true;
		while(flag) {
			String input = getString("请输入要发送数据内容:").trim();
			out.println(input);		//加换行
			if(scan.hasNext()) {		//服务器端有回应
				System.out.println(scan.next());
			}
			if("byebye".equalsIgnoreCase(input)) {
				flag = false;
			}
		}
		scan.close();
		out.close();
		client.close();
	}
	
	public static String getString(String prompt) throws Exception {
		System.out.print(prompt);
		String str = KEYBOARD_INPUT.readLine();
		return str;
	}
}

  此时就实现了最基础的C/S数据通讯操作。

BIO处理模型(多线程与网络编程)

  上述程序存在严重性能缺陷,即服务器只能够为一个线程提供Echo服务,如果说现在服务器需要多人访问时,其他人都在等待连接。
  所以现在可以发现单线程服务器开发本身就是一种不合理的做法,此时最好的解决办法就是将每一个连接到服务器上的客户端都通过一个线程对象来进行处理,即服务器上启动多个线程,每个线程单独为每一个客户端实现Echo支持。

Echo多线程模型(BIO)
6gryCT.png

修改服务器端程序(不必修改客户端)

package per.lyz.demo.server;

import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class EchoServer {
	private static class ClientThread implements Runnable{
		private Socket client = null;		//描述每一个客户端
		private Scanner scan = null;
		private PrintStream out = null;
		private boolean flag = true;		//循环标记
		public ClientThread(Socket client) throws Exception{
			this.client = client;
			this.scan = new Scanner(client.getInputStream());		//客户端输入流
			this.scan.useDelimiter("\n");		//设置分割符
			this.out = new PrintStream(client.getOutputStream());		//客户端输出流
		}
		@Override
		public void run() {
			while(this.flag) {
				if(scan.hasNext()) {		//有数据发送
					String val = scan.next().trim();		//接收发送数据
					if("byebye".equalsIgnoreCase(val)) {
						out.println("See you next time!");
						this.flag = false;		//结束循环
					} else{
						out.println("[Echo]" + val);
					}
				}
			}
			try {
				client.close();
				scan.close();
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] args) throws Exception{
		@SuppressWarnings("resource")
		ServerSocket server = new ServerSocket(9999);		//服务器端监听端口
		System.out.println("等待客户端连接。。。。。。");
		boolean flag = true;
		while(flag) {
			Socket client = server.accept();
			new Thread(new ClientThread(client)).start();;
		}
	}
}

  如果在此类代码中追加一些集合的数据控制,就可以实现一个80年代的聊天室。

UDP程序

  上述程序均属于TCP程序,TCP程序最大的特点是可靠的数据连接,但是网络程序开发中还存在UDP程序(基于数据报的网络编程实现),要想实现UDP程序需要用到两个类:DatagramPacket(数据内容)、DatagramSocket(网络发送接收)。
  数据报就好比发送的短消息,客户端是否接收到与发送者无关。

UDP客户端

package per.lyz.demo.Client;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPClient {

	public static void main(String[] args) throws Exception{
		DatagramSocket client = new DatagramSocket(9999);		//连接到9999端口
		byte data[] = new byte[1024];		//接收信息
		DatagramPacket packet = new DatagramPacket(data, data.length);
		System.out.println("客户端等待接收发送的消息。。。。。。。。");
		client.receive(packet);		//接收消息,所有消息都在data字节数组中
		System.out.println("接收消息内容为:"+ new String(data,0,packet.getLength()));
		client.close();
	}
}

UDP服务端

package per.lyz.demo.server;

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

public class UDPServer {

	public static void main(String[] args) throws Exception {
		DatagramSocket server = new DatagramSocket(9000);		//监听9000端口
		String str = "www.baidu.com!";
		DatagramPacket packet = new DatagramPacket(str.getBytes(),0,str.length(),InetAddress.getByName("localhost"),9999);		//数据包
		server.send(packet);
		System.out.println("发送完成!");
		server.close();
	}
}

  UDP发送的数据是不可靠的,但是由于TCP需要保证可靠的连接所以需要的服务器资源更多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值