网络编程

来源:互联网 发布:时间序列数据分析例子 编辑:程序博客网 时间:2024/05/01 17:32
一、概述

计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。

网络编程就是两个或多个设备之间的数据交换。和普通的单机程序相比,网络程序最大的不同就是需要交换数据的程序运行在不同的计算机上,这样造成数据交换的复杂。想要更好的理解网络编程就要先了解网络模型。

网络模型OSI参考模型和TCP/IP参考模型,如下图所示

ISO指定的OSI参考模型的过于庞大、复杂招到很多批评。与此对照,有技术人员自己开发的TCP/IP协议栈获得更为广泛的应用。TCP/IP参考模型分为四个层次:应用层、传输层、网络互连层和主机到网络层。如下图所示:


网络通信三要素IP地址、端口号、传输协议

①. IP地址

Ⅰ 它是网络中的设备标识。Ⅱ 不易记忆,可用主机名表示,两者存在映射关系。Ⅲ 本机回环地址:127.0.0.1,主机名为:localhost

IP地址分为5类,A类保留给政府机构,B类分配给中等规模的公司,C类分配给任何需要的人,D类用于组播,E类用于实验,各类可容纳的地址数目不同,这5类地址的范围如表:


在以上的地址分类中没有发现127.x.x.x的表示,因为其实保留地址,用作测试,在开发中经常使用127.0.0.1表示本机的IP地址。

②. 端口号

Ⅰ 用于标识进程的逻辑地址,不同进程的标识可以使用360、软媒魔方等查看端口号。

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

③. 传输协议

通信规则,常见TCP和UDP协议

UDP

面向无连接,明确了对方的端口,无论在不在网上,只管传输。若不在就会丢失数据。只求速度,应用于网络视频会议和聊天等应用程序中。协议特点:

Ⅰ 面向无连接,即将数据及源和目的封装成数据包,不建立连接的发送。

Ⅱ 每个数据包的大小限制在64k之内。

Ⅲ 因无连接是不可靠的协议。

Ⅳ 不建立连接,速度快。

TCP

是面向连接的,必须连接成功才能传输数据,应用于下载等程序上

协议特点:

Ⅰ 面向连接,在建立连接后,形成传输数据的通道。

Ⅱ 在连接中进行大数据量的传输。

Ⅲ 经三次握手完成连接,是可靠的协议。

三次握手:第一次本方发送请求,第二次对方确认连接,第三次本方再次确认链接成功。

Ⅳ 必须建立连接,效率稍慢。

二、UDP程序实现

在UDP开发中使用DatagramPacket类包装一条要发送的信息,之后使用DatagramSocket类完成信息的发送操作,这两个类的常用方法:


UDP传输步骤

①. 发送数据

Ⅰ 建立UDPSocket服务。

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

Ⅲ 提供socket服务的发送功能,将数据包发送出去。

Ⅳ 关闭资源。

②. 接受数据

Ⅰ 定义UDPSocket服务。通常会监听一个端口。

Ⅱ 定义一个数据包,用来存储接收到的字节数据。

Ⅲ 通过socket服务的receice方法接受到的数据存入已定义好的数据包中。

Ⅳ 通过数据包对象的方法,将数据取出。

Ⅴ 关闭资源。

示例:通过udp传输方式,将一段文字数据发送出去。

/** * UDP發送端 */public class UDPSend {public static void main(String[] args) throws IOException {System.out.println("发送端启动");// 1. 创建udp服务DatagramSocket datagramSocket = new DatagramSocket();// 2. 准备数据,并封装成数据包byte[] bytes = "Hello World! UDP".getBytes();DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length,InetAddress.getByName("127.0.0.1"), 10000);// 3. 通过socket服务,将数据包发送出去datagramSocket.send(datagramPacket);// 4. 关闭资源datagramSocket.close();}}/** * UDP接收端 */public class UDPReceive {public static void main(String[] args) throws IOException {System.out.println("服务端已启动,等待接收数据");// 1. 创建udp服务,指定端口DatagramSocket datagramSocket = new DatagramSocket(10000);// 2. 定義數據包byte[] bytes = new byte[1024];DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);// 3. 通过DatagramSocket对象的receive方法将接收到的数据存入数据包中datagramSocket.receive(datagramPacket); // 阻塞式方法// 4. 获取数据String ip = datagramPacket.getAddress().getHostAddress(); // IP地址String data = new String(datagramPacket.getData(), 0,datagramPacket.getLength());int port = datagramPacket.getPort(); // 端口号System.out.println("IP地址:" + ip + "\t端口:" + port + "\t接收的数据:" + data);// 5. 关闭资源datagramSocket.close();}}
运行结果:


示例:使用UDP,实现群聊。

/** * 需求:编写一个聊天程序,有接收数据,和发送数据部分 */// 定义发送任务public class UDPChatSend implements Runnable {// 1. 定义socket服务应用private DatagramSocket datagramSocket;public UDPChatSend(DatagramSocket datagramSocket) {this.datagramSocket = datagramSocket;}public void run() {try {// 2. 从键盘录入数据,并将键盘录入的数据封装成数据包DatagramPacket datagramPacket = null;BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));String line = null;while ((line = bufferedReader.readLine()) != null) {byte[] bytes = line.getBytes();datagramPacket = new DatagramPacket(bytes, bytes.length,InetAddress.getByName("127.0.0.255"), 10000);// 3. 发送数据包datagramSocket.send(datagramPacket);if ("over".equals(line)) { // 键盘录入结束标识break;}}} catch (Exception e) {throw new RuntimeException("发送数据失败");} finally {// 4. 关闭资源datagramSocket.close();}}}// 定义接收任务public class UDPChatReceive implements Runnable {private DatagramSocket datagramSocket;public UDPChatReceive(DatagramSocket datagramSocket) {this.datagramSocket = datagramSocket;}public void run() {try {while (true) {// 定義數據包byte[] bytes = new byte[1024];DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);// 通过DatagramSocket对象的receive方法将接收到的数据存入数据包中datagramSocket.receive(datagramPacket); // 阻塞式方法// 获取数据String ip = datagramPacket.getAddress().getHostAddress(); // IP地址String data = new String(datagramPacket.getData(), 0,datagramPacket.getLength());System.out.println("IP地址:" + ip + "\t接收的数据:"+ data);if ("over".equals(data)) {System.out.println("IP:" + ip + "离开了聊天室!");}}} catch (Exception e) {throw new RuntimeException("接收数据失败");}}}public class UDPChatDemo {public static void main(String[] args) throws IOException {DatagramSocket send = new DatagramSocket(8888);DatagramSocket receive = new DatagramSocket(10000);new Thread(new UDPChatSend(send)).start();new Thread(new UDPChatReceive(receive)).start();}}
三、TCP程序实现
在java中使用Socket(套接字)完成TCP程序的开发,使用此类可以方便地建立可靠的、双向的、持续的、点对点的通信连接。

在Socket的程序开发中,服务端使用ServerSocket等待客户端的连接,每个客户端都使用一个Socket对象表示。

ServerSocket类与Socket类

1. ServerSocket类的常用方法:

// 创建ServerSocket实例,并指定监听端口public ServerSocket(int port) throws IOException// 等待客户端连接,此方法连接之前一直阻塞public Socket accept() throws IOException// 返回服务端的IP地址public InetAddress getInetAddress() // 关闭ServetSocketpublic void close() throws IOException
2. Socket类的常用方法

// 构造Socket对象,同时指定要链接服务器的主机名称及连接端口public Socket(String host, int port) UnknownHostException, IOException// 返回此套接字的输入流public InputStream getInputStream() throws IOException// 返回此套接字的输出流public OutputStream getOutputStream() throws IOException// 关闭此Socketpublic void close() throws IOException
示例:客户端给服务端发送数据,服务端收到之后,给客户端反馈信息
/*** 客户端*/public class TCPClient {public static void main(String[] args) throws IOException {// 1. 创建客户端Socket服务,指定目的和端口Socket socket = new Socket("127.0.0.1", 10000);// 2. 獲取Socket流中輸出流,發送數據OutputStream out = socket.getOutputStream();out.write("Hello".getBytes());// 3, 获取Socket流中输入流,用来接收服务端的反馈信息并打印InputStream in = socket.getInputStream();byte[] bytes = new byte[1024];int len = in.read(bytes);// 輸出接收到的數據System.out.println(new String(bytes, 0, len));// 4. 關閉資源socket.close(); }}/*** 服务端*/public class TCPServer {public static void main(String[] args) throws IOException {// 创建服务端的Socket服务,并监听一个端口ServerSocket serverSocket = new ServerSocket(10000);// 通過accept方法獲取連接過來的客戶端對象Socket socket = serverSocket.accept();// 获取客户端IPString ip = socket.getInetAddress().getHostAddress();System.out.println(ip + "connection...");// 獲取對應客戶端對應的讀取流讀取發送過來的數據,並打印InputStream in = socket.getInputStream();byte[] bytes = new byte[1024];int len = in.read(bytes);System.out.println(new String(bytes, 0, len));// 调用对应的客户端的输出流写入返回数据OutputStream out = socket.getOutputStream();out.write("收到".getBytes());// 关闭资源socket.close();serverSocket.close();}}
实例:客户端通过键盘录入向服务端发送文本,服务端会将文本转化成大写返回给客户端,当客户端输入over,转换结束。

public class TransClient {public static void main(String[] args) throws UnknownHostException, IOException {// 创建Socket服务Socket socket = new Socket("127.0.0.1", 10000);// 定義讀取鍵盤數據的流對象BufferedReader br = new BufferedReader(new InputStreamReader(System.in));// 将数据写入到Socket输出流。发送给服务端PrintWriter out = new PrintWriter(socket.getOutputStream(), true);  // 自动涮新// 定义一个socket读取流,读取服务端返回的大写信息BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));String line = null;while ((line = br.readLine()) != null) {if ("over".equals(line)) {break;}out.println(line);  // 相当于out.write(line); out.nextLine();// 读取返回的信息String data = in.readLine();System.out.println(data);}// 關閉資源br.close();socket.close();}}public class TransServer {public static void main(String[] args) throws IOException {// 創建服務端的ServerSocket服務,並指定監聽端口ServerSocket serverSocket = new ServerSocket(10000);// 获取客户端连接Socket socket = serverSocket.accept();// 獲取客戶端ipSystem.out.println(socket.getInetAddress().getHostAddress() + "connection...");// 读取客户端发送数据BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 將大些數據寫入到socket輸出流,發送給客戶端PrintWriter out = new PrintWriter(socket.getOutputStream(), true);String line = null;while((line = in.readLine()) != null) {System.out.println(line);out.println(line.toUpperCase());}socket.close();serverSocket.close();}}
实例:向服务端上传一个文件,服务端返回一条信息。

/**客户端数据发送完毕,服务端仍然等待读取数据,下面是解决办法:方法一:定义结束标识,先将标识发送给服务端,让服务端接收到结束标识,然后再发送上传数据。缺点:可能上传文件中包含结束标识,导致上传提前结束。方法二:定义时间戳作为标识。方法三:通过socket方法中的shutdownOutput(),关闭输入流资源,从而结束传输流。推荐使用*/public class UploadTextClient {public static void main(String[] args) throws UnknownHostException,IOException {Socket socket = new Socket("127.0.0.1", 10000);BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("E:\\client.txt")));// 将数据写入到Socket输出流。发送给服务端PrintWriter out = new PrintWriter(socket.getOutputStream(), true); // 自动涮新// 定义一个socket读取流,读取服务端返回的大写信息BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));String line = null;while ((line = br.readLine()) != null) {out.println(line); // 相当于out.write(line); out.nextLine();}socket.shutdownOutput();// 读取返回的信息System.out.println(in.readLine());// 關閉資源br.close();socket.close();}}public class UploadTextServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(10000);Socket socket = serverSocket.accept();System.out.println(socket.getInetAddress().getHostAddress() + "connection...");BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter printWriter = new PrintWriter(new FileWriter("E:\\server.txt"), true);// BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));PrintWriter out = new PrintWriter(socket.getOutputStream(), true);String line = null;while ((line = in.readLine()) != null) {printWriter.println(line);}out.println("上傳成功");// out.write("上傳成功");// out.newLine();// out.flush();printWriter.close();socket.close();serverSocket.close();}}
实例:用TCP并发上传图片

/** * 服務端,接收客戶端發送過來的圖片數據,進行存儲後,回饋一個上傳成功字樣 */public class UploadPicServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(10000);while (true) {Socket socket = serverSocket.accept();String ip = socket.getInetAddress().getHostAddress();System.out.println(ip + "connection...");InputStream in = socket.getInputStream();File dir = new File("E:\\jpg");if (!dir.exists())dir.mkdir();int count = 1;File file = new File(dir, ip + ".jpg");while (file.exists()) {file = new File(dir, ip + "(" + (count++) + ").jpg");}FileOutputStream fos = new FileOutputStream(file);byte[] bytes = new byte[1024];int len = 0;while ((len = in.read(bytes)) != -1) {fos.write(bytes, 0, len);fos.flush();}OutputStream out = socket.getOutputStream();out.write("上传成功".getBytes());fos.close();socket.close();}}}public class UploadPicClient {public static void main(String[] args) throws UnknownHostException,IOException {Socket socket = new Socket("127.0.0.1", 10000);FileInputStream fis = new FileInputStream("E:\\client.jpeg");OutputStream out = socket.getOutputStream();byte[] bytes = new byte[1024];int len = 0;while ((len = fis.read(bytes)) != -1) {out.write(bytes, 0, len);}socket.shutdownOutput();InputStream in = socket.getInputStream();byte[] bufIn = new byte[1024];int lenIn = in.read(bufIn);String info = new String(bufIn, 0, lenIn);System.out.println(info);fis.close();socket.close();}}
三、客户端与服务端

常见的客户端与浏览器

客户端:浏览器

服务器:Tomcat

1. 通过自定义服务端,查看浏览器给服务端发送的数据。自定义服务端:

public class MyServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(9090);Socket socket = serverSocket.accept();System.out.println(socket.getInetAddress().getHostAddress() + "...connected");InputStream in = socket.getInputStream();byte[] bytes = new byte[1024];int len = in.read(bytes);String text = new String(bytes, 0, len);System.out.println(text);PrintWriter out = new PrintWriter(socket.getOutputStream(), true);out.println("欢迎光临");socket.close();serverSocket.close();}}
浏览器查看:



结果是:


分析结果:

http协议请求头GET / HTTP/1.1    // 请求行 包含:请求方式(GET,POST)空格 请求的资源路径 空格 http协议版本// 下面这些是请求头中属性信息Accept: text/html, application/xhtml+xml, image/jxr, */*Accept-Language: zh-Hans-CN,zh-Hans;q=0.5User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like GeckoAccept-Encoding: gzip, deflateHost: 127.0.0.1:9090Connection: Keep-Alive空行请求体(此请求没有请求体)
2. 模拟一个浏览器

public class MyBrowser {public static void main(String[] args) throws UnknownHostException, IOException {Socket socket = new Socket("127.0.0.1", 8080);// 發送一些Tomcat可以識别的信息,比如http協議規則信息PrintWriter out = new PrintWriter(socket.getOutputStream(), true);out.println("GET /Struts2/ HTTP/1.1");out.println("Accept: text/html, application/xhtml+xml, image/jxr, */*");out.println("Host: 127.0.0.1:8080");out.println("Connection: close");out.println();out.println();InputStream in = socket.getInputStream();byte[] bytes = new byte[1024];int len = in.read(bytes);System.out.println(new String(bytes, 0, len));socket.close();}}
启动Tomcat服务器,我的Tomcat中有一个Struts2的应用,这里用于测试。测试结果:



分析结果:

// 这些事Http协议的应答消息HTTP/1.1 200 OK   // 应答行 http协议版本 应答状态码 应答状态码消息描述// 应答消息头属性信息Server: Apache-Coyote/1.1Set-Cookie: JSESSIONID=339E92810A3018C16829C421AF28B548; Path=/Struts2/; HttpOnlyContent-Type: text/html;charset=UTF-8Content-Length: 840Date: Fri, 25 Sep 2015 09:12:08 GMTConnection: close// 相应体<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>INNDEX</title></head><body>
四、http1.0协议和http1.1协议区别

在HTTP/1.0中,实现为每个请求/响应交换使用新的连接。在HTTP/1.1中,一个连接可用于一次或多次请求/响应交换,这是它们之间最大的区别。

一个典型的网页,由一个html文件和内嵌的各类元素组成的,这些元素包括页面内的图片、css文件、javascript文件等等。每一个内嵌的元素在HTTP协议的层面上和那个html文件是没有区别的,也就是都需要浏览器去服务器上抓下来。早期典型的浏览器是这样实现的:当用户敲入网址之后,浏览器和服务器建立连接,请求这个html页面,然后边接收服务器发送的html页面,便解析,碰到内嵌的元素,可以立即开第二条连接请求。另外如果内嵌元素很多,它可能会开很多条连接同时请求。当所有需要的元素都下载完毕之后,浏览器就会将页面画出来,这个过程就是早期的HTTP/1.0协议所设想的浏览器实现。

HTTP/1.1也就是同一条HTTP连接,同时处理多个请求,同时 用一定的机制保证各个请求之间的分离性。具体的操作过程是:服务器给浏览器发送回应之后,并不马上关闭连接;浏览器判断上一个请求的回应已经收发的情况下,可以在这同一个连接上发第二个请求。但是,由于服务器上保持连接要占用一定的资源,所以一般服务器不会永久保持持久连接,而且也不推荐浏览器和服务器之间建立过多的持久化连接。

五、CS与BS的区别

C/S又称Client/Server或客户/服务器模式。服务器通常采用高性能的PC、工作站或小型机,并采用大型数据库系统,如Oracle、 Sysbase或SQL Server。客户端需要安装专用的哭客户端软件。

B/S是Brower/Server的缩写,客户机上只要安装一个浏览器,服务端安装Oracle、 Sysbase或SQL Server等数据库。浏览器通过Web Server同数据进行数据交互。

C/S的优缺点:

优点:客户端响应速度快。

缺点:客户端需要安装专用的客户端软件,涉及安装的工作量,其次任何用一台电脑出问题,如病毒、硬件损坏,都需要进行安装与维护。还有,软件升级,每台客户机需要重新安装,其维护和升级成本高。操作系统也会有限制。

B/S的优点:

可以在任何地方进行操作而不安装任何专门的软件。只需一台可上网的电脑就能使用,客户端零维护。系统扩展非常容易,只要能上网。



0 0
原创粉丝点击