Java网络编程

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

网络编程简介

  网络的核心定义在于:有两台以上的电脑就称为网络。实际上在世界上产生的第一台电脑之后就有人开始去思考如何生产更多的电脑并且进行有效连接。
  网络连接的目的不仅仅是为了进行电脑的串联,更多的情况下是为了进行彼此之间的数据通讯,包括现在所谓的网络游戏本质上还是网络通讯的问题,而在通讯的实现上就产生了一系列的处理协议:IP、TCP、UDP等等,也就是说所谓的网络编程,实际上实现的就是一个数据的通讯操作而已,只不过这个通讯操作需要分为客户端和服务端。
  于是针对网络程序的开发就有了两种模型:

  • C/S(Client/Server、客户端与服务端):要开发出两套程序,一套程序为客户端,另外一套为服务端,如果现在服务端发生了改变之后客户端也应该进行更新处理,这种开发可以由开发者自定义传输协议,并且使用一些比较私密的端口,所以安全性是比较高的,但是开发与维护成本比较高;
  • B/S(Browser/Server、浏览器与服务端):只开发一套服务端的程序,而后利用浏览器作为客户端进行访问,这种开发与维护的成本较低(只有一套程序),但是由于其使用的是公共的HTTP协议并且使用的公共的80端口,所以其安全性相对较差,现在的开发基本上以“B/S”结构为主。
      本次所要的网络编程主要就是C/S程序模型,其分为两种开发:TCP(可靠的数据连接)、UDP(不可靠的数据连接);

TCP程序的基本实现

  TCP的程序开发是网络程序的最基本的开发模型,其核心的特点是使用两个类实现数据的交互处理:ServerSocket(服务端)、Socket(客户端)。

ServerSocket与Socket

  ServerSocket的主要目的是设置服务器的监听端口,而Socket需要指明要连接的服务器地址和端口。下面实现一个最简单的数据处理操作,即Echo程序实现。

Echo模型

范例:实现服务端的定义

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 scanner = new Scanner(client.getInputStream());//客户端输入流
        scanner.useDelimiter("\n");//设置分隔符
        PrintStream out = new PrintStream(client.getOutputStream());//客户端输出流
        boolean flag = true;//循环标记
        while (flag) {
            if (scanner.hasNext()) {//现在有数据发送
                String val = scanner.next().trim();//接收发送的数据
                if ("exit".equalsIgnoreCase(val)) {
                    out.println("bye");
                    flag = false;
                } else {
                    out.println("【ECHO】" + val);
                    out.flush();
                }
            }
        }
        scanner.close();
        out.close();
        client.close();
        server.close();
    }
}

范例:实现客户端的定义

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_BUF = new BufferedReader(new InputStreamReader(System.in));
    public static void main(String[] args) throws Exception{
        Socket client = new Socket("localhost",9999);//定义服务端连接信息
        //现在的客户端需要有输入与输出的操作支持,所以依然要准备出Scanner与PrintWriter
        Scanner scanner=new Scanner(client.getInputStream());//接收服务端的输入内容
        scanner.useDelimiter("\n");
        PrintStream out = new PrintStream(client.getOutputStream());//向服务器发送内容
        boolean flag=true;//循环标记
        while (flag){
            String input = getString("请输入要发送的内容:");
            out.println(input);//加换行
            if(scanner.hasNext()){//服务端有回应了
                System.out.println(scanner.next());
            }
            if("exit".equalsIgnoreCase(input)){
                flag =false;
            }
        }
        scanner.close();
        out.close();
        client.close();
    }
    public static String getString(String prompt)throws Exception{
        System.out.print(prompt);
        String str=KEYBOARD_BUF.readLine();
        return str;
    }
}

  此时就实现了一个最基础的客户端与服务端之间的数据通讯操作。

多线程与网络开发

  现在尽管已经实现了一个标准的网络程序开发,但是在整个的开发过程之中存在严重的性能缺陷,因为该服务器只能够为一个线程提供Echo服务,如果说现在的服务器需要有多人进行连接访问的时候,那么其他的使用者将无法连接(等待连接)。
  所以现在就可以发现单线程的服务器开发本身就是一种不合理的做法,那么此时最好的解决方案将每一个连接到服务器上的客户端都通过一个线程对象来进行处理,即:服务器上启动多个线程,每一个线程单独为每一个客户端实现Echo服务支持。

Echo多线程模型(BIO)

范例:修改服务器端程序

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 scanner = null;
        private PrintStream out = null;
        private boolean flag = true;//循环标记
        public ClientThread(Socket client) throws Exception {
            this.client = client;
            scanner = new Scanner(client.getInputStream());//客户端输入流
            scanner.useDelimiter("\n");//设置分隔符
            out = new PrintStream(client.getOutputStream());//客户端输出流
        }
        @Override
        public void run() {
            while (flag) {
                if (scanner.hasNext()) {//现在有数据发送
                    String val = scanner.next().trim();//接收发送的数据
                    if ("exit".equalsIgnoreCase(val)) {
                        out.println("bye");
                        flag = false;
                    } else {
                        out.println("【ECHO】" + val);
                        out.flush();
                    }
                }
            }
            scanner.close();
            out.close();
            try {
                if (client != null)
                    client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(9999);//设置服务端的监听端口
        System.out.println("等待客户端连接................");
        //1、首先需要先接收客户端发来的信息,而后才可以将信息处理后发送回客户端
        boolean flag = true;//循环标记
        while (flag) {
            new Thread(new ClientThread(server.accept())).start();
        }
        server.close();
    }
}

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

数据报发送与接收(UDP)

  之前所见到的都属于TCP程序开发范畴,TCP程序最大的特点是可靠的网络连接,但是在网络程序开发之中还存在一种UDP程序,基于数据报的网络编程实现,如果想要实现UDP程序需要两个类:DatagramPacket(数据内容)、DatagramSocket(网络的发送与接收)。数据报就好比发送的短消息一样,客户端是否收到与发送者无关。
范例:实现一个UDP客户端

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);
        System.out.println("接收的消息内容为:"+new String(data,0,packet.getLength()));
    }
}

范例:实现一个UDP服务端

import  java.net.InetAddress;
import  java.net.DatagramPacket;
import  java.net.DatagramSocket;
public class UDPServer {
    public static void main(String[] args)throws Exception {
        DatagramSocket server = new DatagramSocket(9000);//连接到9999端口
        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由于需要保证可靠的连接,所以所需要的服务器资源就越多。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342