一.java网络编程
所谓的网络编程指的就是多台主机之间的数据通讯操作.
--网络编程简介
网络的核心定义:有两台以上的电脑就成为网络.实际上在世界上产生第一台电脑之后,就有人开始思考如何能够将多台的电脑生产出来,并且能够进行有效的了解.网络连接的目的不仅仅是为了进行电脑的串联,更多的情况下是为了进行多台电脑之间的数据交换,就像如今的网络游戏,其本质上还是网络通讯的问题.而在通讯的实现上,就产生了一系列的处理协议:IP,TCP,UDP等等,所谓的网络编程实际上实现的就是数据的通讯操作而已.只不过这个通讯操作需要分为客户端与服务器端.
于是针对于网络程序的开发就有了两种模型:
C/S(Client/Server,客户端与服务器端) :要开发出两套程序,一套程序为客户端,一套程序为服务器端.在服务器端发生了改变之后客户端也应该进行更新处理;这种开发可以有开发者自定义传输协议,并且使用一些比较私密的端口,所以安全性是比较高的,但是开发与维护成本比较高.
B/S(Browse/Server,浏览器与服务器端): 只开发一套服务器端的程序,而后利用浏览器作为客户端进行访问.这种开发与维护的成本较低(只有一套程序).但是由于其使用的是公共的HTTP协议并且使用的是公共的80端口,所以其安全性相对较差.现在的开发基本上以"B/S"的结构为主.
本次所说的网络编程主要是"C/S"程序模型,其分为两种程序开发:TCP(可靠的数据连接),UDP(不可靠的数据连接);
二.TCP程序的基本实现
TPCP的程序开发是网络程序的最基本的开发模型,其核心的特点是使用两个类实现数据的交互处理,所有的服务器在网上都需要有监听端口:
ServerSocket(服务器端):指定监听端口,通过Socket来描述客户端.
Socket(客户端):Socket需要指明要连接的服务器地址与端口.
--范例:实现最简单的数据处理操作,即:Echo程序实现,所谓的Echo是最典型的服务器端与客户端的网络通信模型,客户端使用键盘输入数据,将数据发送到服务端,所发送的数据只能是字节数据.现在实现服务器端的定义:(如果此时需要对程序进行测试,最好的方法是直接使用telnet的命令执行,但是此命令在windows7之后已经变为了默认不开启的状态,因此如果想要启用,需要单独启用此命令:控制面板-->程序和功能-->启用或关闭Windows功能-->telnet)
使用cmd进入telnet界面后监听服务器端口(需要先开启服务器):
1 package 网络编程;
2
3 import java.io.PrintStream;
4 import java.io.PrintWriter;
5 import java.net.ServerSocket;
6 import java.net.Socket;
7 import java.util.Scanner;
8
9 /**
10 * @author : S K Y
11 * @version :0.0.1
12 */
13 public class ServerSocketDemo {
14 public static void main(String[] args) throws Exception {
15 ServerSocket server = new ServerSocket(9999); //设置服务器的监听端口
16 System.out.println("等待客户端连接............");
17 Socket client = server.accept();//有客户端连接
18 //1.首先需要先接受客户端发来的信息,而后才可以将信息处理之后发送回客户端
19 Scanner scanner = new Scanner(client.getInputStream()); //客户端输入流
20 scanner.useDelimiter("\n"); //设置分隔符
21 PrintStream out = new PrintStream(client.getOutputStream()); //客户端输出流
22 boolean flag = true;
23 while (flag) {
24 if (scanner.hasNext()) { //现在有数据发送
25 String val = scanner.next().trim(); //接受发送的数据
26 if ("byebye".equalsIgnoreCase(val)) {
27 out.println("ByeByeBye.....");
28 flag = false; //结束循环
29 } else {
30 out.println("[ECHO]" + val);
31 }
32 }
33 }
34 out.close();
35 scanner.close();
36 client.close();
37 server.close();
38 }
39 }
1 package 网络编程;
2
3 import java.io.*;
4 import java.net.Socket;
5 import java.util.Scanner;
6
7 /**
8 * @author : S K Y
9 * @version :0.0.1
10 */
11 public class SocketDemo {
12 private static final BufferedReader KEYBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in));
13
14 public static void main(String[] args) throws Exception {
15 Socket client = new Socket("localhost", 9999); //定义服务端的连接信息
16 //现在的客户端需要有输入和输出支持,所以依然要准备出Scanner与PrintWriter
17 Scanner scanner = new Scanner(client.getInputStream()); //从服务器端输入内容
18 scanner.useDelimiter("\n");
19 PrintStream out = new PrintStream(client.getOutputStream()); //向服务器端发送内容
20 boolean flag = true;
21 while (flag) {
22 String input = getString("请输入要发送的内容:").trim();
23 out.println(input); //加换行
24 if (scanner.hasNext()) { //服务器端有回应了
25 System.out.println(scanner.next());
26 }
27 if ("byebye".equalsIgnoreCase(input)) {
28 flag = false;
29 }
30 }
31 scanner.close();
32 out.close();
33 client.close();
34
35 }
36
37 public static String getString(String prompt) throws IOException {
38 System.out.println(prompt);
39 String str = KEYBOARD_INPUT.readLine();
40 return str + "\n";
41 }
42 }
三.多线程与网络编程
现在已经实现了标准的网络程序开发,但是在整个的开发过程之中,本程序存在有严重的性能缺陷,因为该服务器只能为一个线程提供Wcho服务,如果说现在的服务器需要有多人进行连接访问的时候,那么其他的使用者将无法连接(等待连接),
--可以发现单线程的服务器开发本身就是一种不合理的做法,此时最好的解决办法就是将每一个连接到服务器上的客户端都通过一个线程对象来进行描述处理.即:在服务器上启动多个线程,每一个线程单独为每一个客户端实现Echo服务支持.
--Echo的多线程模型:
客户端1 线程对象1
客户端2 -->Socket对象(accaccept()方法表示客户端的连接操作) -->服务器监听端口 --> 线程对象2 --> 服务器(实现线程对象的操作管理)
客户端3 线程对象3
--范例:修改服务器端程序
1 package 网络编程;
2
3 import java.io.IOException;
4 import java.io.PrintStream;
5 import java.net.ServerSocket;
6 import java.net.Socket;
7 import java.util.Scanner;
8
9 /**
10 * @author : S K Y
11 * @version :0.0.1
12 */
13 public class ServerSocketDemo {
14 public static void main(String[] args) throws Exception {
15 ServerSocket server = new ServerSocket(9999); //设置服务器的监听端口
16 System.out.println("等待客户端连接............");
17 boolean flag = true; //循环标记
18 while (flag) {
19 Socket client = server.accept();//有客户端连接
20 new Thread(new ClientThread(client)).start();
21 }
22 server.close();
23 }
24 }
25
26 class ClientThread implements Runnable {
27 private Socket client = null; //描述每一个不同的客户端
28 private Scanner scan;
29 private PrintStream out;
30 private boolean flag = true; //循环处理标记
31
32 public ClientThread(Socket client) throws IOException {
33 this.client = client;
34 scan = new Scanner(client.getInputStream()); //客户端输入流
35 scan.useDelimiter("\n");
36 out = new PrintStream(client.getOutputStream()); //客户端输出流
37 }
38
39 @Override
40 public void run() {
41 while (flag) {
42 if (scan.hasNext()) { //现在有数据发送
43 String val = scan.next().trim(); //接受发送的数据
44 if ("byebye".equalsIgnoreCase(val)) {
45 out.println("ByeByeBye.....");
46 flag = false; //结束循环
47 } else {
48 out.println("[ECHO]" + val);
49 }
50 }
51 }
52 out.close();
53 scan.close();
54 try {
55 client.close();
56 } catch (IOException e) {
57 e.printStackTrace();
58 }
59 }
60 }
--如果你在这类的代码中在追加一些集合的数据控制,实际上就可以实现一个较为简单的聊天室....
四.数据报发送与接收
在上述所见到的都属于TCP的程序的开发范畴,TCP的程序最大的特点是可靠的网络连接.但是在程序开发之中还存在有一种叫做UDP(基于数据报的网络编程实现).如果要想实现UDP程序的话,需要使用到两个类:
DatagramPacket: 数据内容
DatagramSocket: 网络发送与接收
--数据报就好比发送的短消息一样,客户端是否接收到与发送者无关.实现一个UDP的客户端:
1 package 网络编程.UDP数字报;
2
3 import java.io.IOException;
4 import java.net.DatagramPacket;
5 import java.net.DatagramSocket;
6
7 /**
8 * @author : S K Y
9 * @version :0.0.1
10 */
11 public class UDPClient {
12 public static void main(String[] args) throws IOException { //接收数据信息
13 DatagramSocket client = new DatagramSocket(9999); //连接到9999端口
14 byte[] data = new byte[1024]; //接收消息
15 DatagramPacket packet = new DatagramPacket(data, data.length); //接收数据的对象.接收数据的长度
16 System.out.println("客户端等待发送的消息....");
17 client.receive(packet); //接收消息,所有的消息都在data的字节数组当中
18 System.out.println("接收到的消息内容为: " + new String(data, 0, packet.getLength()));
19 client.close();
20 }
21 }
--服务端:
1 package 网络编程.UDP数字报;
2
3 import java.io.IOException;
4 import java.net.DatagramPacket;
5 import java.net.DatagramSocket;
6 import java.net.InetAddress;
7
8 /**
9 * @author : S K Y
10 * @version :0.0.1
11 */
12 public class UDPServer {
13 public static void main(String[] args) throws IOException {
14 DatagramSocket server = new DatagramSocket(9000); //连接到9000端口(连接端口)
15 String str = "你好,今天的天气是晴天..";
16 byte[] data = str.getBytes();
17 DatagramPacket packet = new DatagramPacket(data, 0, data.length
18 , InetAddress.getByName("localhost"), 9999); //发送数据(客户端所在端口)
19 server.send(packet); //发送消息
20 System.out.println("消息发送完毕...");
21 server.close();
22 }
23 }
--优先运行客户端后再运行服务器端,可以发现客户端将正常接受到服务端的数据,如果优先运行了服务器端,那么客户端将无法接收到本次的消息发送,因此可以发现UDP所谓的不可靠的消息连接指的是客户端是否接收到消息与服务器端无关.
--UDP发送的数据一定是不可靠的,TCP由于需要保证可靠的连接,所以需要的服务器的资源就越多.