第二课 简单的客户端服务端通信

1 TCP/IP 编程练习

1.1 基于TCP的Socket通信

  • Java语言的基于套接字编程分为服务端编程和客户端编程,其通信模型如图所示:

基于TCP的Socket通信


  • 客户端Socket的工作过程包含以下四个基本步骤:
    • 创建Socket:根据指定服务端的IP地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常,创建的同时会自动向服务器发起连接
    • 打开连接到Socket的输入/出流:使用getInputStream() / getOutputStream()方法获得输入/出流
    • 按照一定的协议对 Socket 进行读/写操作
    • 关闭 Socket

  • 服务器程序的工作过程包含以下四个基本步骤:
    • 调用 ServerSocket(int port): 创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。
    • 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
    • 调用该 Socket 类对象的 getOutputStream()getInputStream():获取输出/入流,开始网络数据的发送和接收
    • 关闭ServerSocket 和 Socket 对象:客户端访问结束,关闭通信套接字

ServerSocket 和 Socket
ServerSocket 对象负责等待客户端请求建立套接字连接,类似于邮局某个窗口中的业务员。即,服务器必须事先建立一个等待客户端请求建立套接字连接的 ServerSocket 对象。所谓接受客户的套接字请求,就是 accept() 方法返回的一个 Socket 对象

1.2 例题1:客户端向服务器发送一段话

package NetDev;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class ClientAndServers {
	public static void main(String[] args) {
		// 先启动服务器,然后客户端进行接入
		new Thread() {
			@Override
			public void run() {
				Servers();
			}
		}.start();
		Client();
	}

	public static void Client() {
		Socket socket = null;
		OutputStream os = null;
		try {
			InetAddress inet = InetAddress.getByName("127.0.0.1");
			socket = new Socket(inet, 8859);
			os = socket.getOutputStream();
			os.write("你好啊,我是客户端".getBytes());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				socket.close();
				os.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void Servers() {
		ServerSocket ss = null;
		Socket accept = null;
		InputStream is = null;
		ByteArrayOutputStream baos = null;
		try {
			// 创建服务器端的ServerSocket,指明自己的端口号
			ss = new ServerSocket(8859);
			// 调用accept()方法,表示接收来自于客户端的Socket
			accept = ss.accept();
			// 获取输入流
			is = accept.getInputStream();

			// 读取输入流中的数据
			byte[] buf = new byte[20];
			int len = 0;
			baos = new ByteArrayOutputStream();
			while ((len = is.read(buf)) != -1) {
				baos.write(buf, 0, len);
			}

			System.out.println(baos.toString());
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				baos.close();
				is.close();
				accept.close();
				ss.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

1.3 例题2:客户端向服务器发送文件

package NetDev;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 客户端向服务器上传文件
 * 
 * @author Yorick
 *
 */
public class ClientAndServers_File {
	public static void main(String[] args) {
		new Thread() {
			@Override
			public void run() {
				Servers();
			}
		}.start();
		Client();
	}

	public static void Client() {
		InetAddress inet = null;
		Socket socket = null;
		OutputStream outputStream = null;
		FileInputStream fileInputStream = null;
		try {
			inet = InetAddress.getByName("127.0.0.1");
			socket = new Socket(inet, 8899);
			// 获取输出流,从客户端将数据发送到服务端的流
			outputStream = socket.getOutputStream();
			// 获取文件流,将文件以流的方式从本地读取到向服务端发送的流中
			fileInputStream = new FileInputStream(new File("C:\\Users\\Yorick\\Desktop\\Head.jpg"));
			// 读取文件
			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = fileInputStream.read(buffer)) != -1) {
				outputStream.write(buffer);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				socket.close();
				outputStream.close();
				fileInputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void Servers() {
		ServerSocket serverSocket = null;
		Socket accept = null;
		InputStream inputStream = null;
		FileOutputStream fileOutputStream = null;
		try {
			serverSocket = new ServerSocket(8899);
			// 可以接收客户端发送的信息
			accept = serverSocket.accept();
			// 获取客户端发来的流
			inputStream = accept.getInputStream();
			// 将客户端发来的流中的信息写入文件中
			fileOutputStream = new FileOutputStream(new File("C:\\Users\\Yorick\\Desktop\\Head_Server.jpg"));
			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = inputStream.read(buffer)) != -1) {
				fileOutputStream.write(buffer, 0, len);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				serverSocket.close();
				accept.close();
				inputStream.close();
				fileOutputStream.close();
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}
}

2 UDP 编程练习

2.1 基于 UDP 的Socket通信

  • 类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序
  • UDP 数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP 数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
  • DatagramPacket 对象封装了 UDP 数据报,在数据报中包含了发送端的 IP 地址和端口号,以及接收端的 IP 地址和端口号
  • UDP 协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接受方的连接。如同发快递包裹一样。
  • UDP 网络通信的流程
    • DatagramSocket 和 DatagramPacket
    • 建立发送端,接收端(发送端和接收端是两个独立的运行程序)
    • 建立数据包
    • 调用 Socket 的发送、接收方法
    • 关闭 Socket

2.2 例题1:发送数据到服务器

package NetDev;

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

public class UDP_SenderAndReceiver {
	public static void main(String[] args) {
		new Thread() {
			@Override
			public void run() {
				Receiver();
			}
		}.start();
		Sender();
	}

	public static void Sender() {
		DatagramSocket datagramSocket = null;
		DatagramPacket datagramPacket = null;
		try {
			// 创建 DatagramSocket 对象,建立连接
			datagramSocket = new DatagramSocket();
			// 将数据封装到 DatagramPacket 对象中(包括数据,发送地址 --IP,端口号)
			byte[] data = "发送端发送".getBytes();
			InetAddress localHost = InetAddress.getLocalHost();
			datagramPacket = new DatagramPacket(data, 0, data.length, localHost, 9898);
			
			// 发送数据
			datagramSocket.send(datagramPacket);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			datagramSocket.close();
		}

	}

	public static void Receiver() {
		DatagramPacket datagramPacket = null;
		DatagramSocket datagramSocket = null;
		try {
			// 创建 DatagramSocket 对象,并指定端口号
			datagramSocket = new DatagramSocket(9898);
			
			// 创建 DatagramPacket 对象
			byte[] data = new byte[100];
			datagramPacket = new DatagramPacket(data,0,data.length);
			
			// 接收数据
			datagramSocket.receive(datagramPacket);
			
			// 输出数据
			System.out.println(new String (datagramPacket.getData(),0,datagramPacket.getLength()));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			datagramSocket.close();
		}
	}
}

3 URL 编程

3.1 解析URL

package NetDev;

import java.net.MalformedURLException;
import java.net.URL;

public class URL_Test {
	public static void main(String[] args) {
		try {
			URL url = new URL("https://editor.csdn.net/md?articleId=108099857");
			System.out.println("协议名:" + url.getProtocol());
			System.out.println("主机名:" + url.getHost());
			System.out.println("端口号:" + url.getPort());
			System.out.println("文件路径:" + url.getPath());
			System.out.println("文件名:" + url.getFile());
			System.out.println("查询名:" + url.getQuery());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	}
}

// 运行结果
// 协议名:https
// 主机名:editor.csdn.net
// 端口号:-1
// 文件路径:/md
// 文件名:/md?articleId=108099857
// 查询名:articleId=108099857

3.2 从 Tomcat 服务器上下载图片

public static void DownloadPic() {
	URL url = null;
	HttpURLConnection openConnection = null;
	InputStream inputStream = null;
	FileOutputStream fileOutputStream = null;
	try {
		// 指定连接
		url = new URL("http://localhost:8080/examples/Collection.jpg");
		// 获取连接
		openConnection = (HttpURLConnection) url.openConnection();
		// 打开连接
		openConnection.connect();
		// 获取输入流
		inputStream = openConnection.getInputStream();
		// 输出到本地文件中完成下载
		fileOutputStream = new FileOutputStream(new File("C:\\Users\\Yorick_PC\\Desktop\\Test\\Collection.jpg"));
		byte[] buffer = new byte[1024];
		int len = 0;
		while ((len = inputStream.read(buffer)) != -1) {
			fileOutputStream.write(buffer);
		}
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		if (fileOutputStream != null) {
			try {
				fileOutputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if (openConnection != null) {
			// 关闭URL的连接
			openConnection.disconnect();
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值