网络编程系列第(三)篇---Socket

Socket是什么

Socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。

----------------以上内容来自百度百科-------------------

使用TCP

服务端代码

public class TCPServer {

  // 启动服务
  public void start() {
    try {
        // 1.创建一个服务端的socket
        ServerSocket serverSocket = new ServerSocket(12345);
        System.out.println("服务器等待与客户端的连接...");
        int count=0;
        while (true) {
            // 2.调用accept方法开始监听,等待客户端的连接
            Socket client = serverSocket.accept();
            count++;
            System.out.println("客户端请求次数:"+count);
            new reponseClient(client);
        }

    } catch (IOException e) {
        System.out.println("服务器异常:" + e.getMessage());
    }

}

// 响应客户端
private class reponseClient extends Thread {

    private Socket clinet;

    public reponseClient(Socket client) {
        this.clinet = client;
        start();
    }

    public void run() {
        try {
            // 3.获取输入流,并读取客户端信息
            InputStream is = clinet.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);

            String info = null;
            while ((info = br.readLine()) != null) {
                System.out.println("我是服务器,客户端说:" + info);
            }
            clinet.shutdownInput(); // 关闭输入流

            // 4.获取输出流,响应客户端的请求
            OutputStream os = clinet.getOutputStream();
            PrintWriter pw = new PrintWriter(os);
            pw.write("欢迎你登录");
            pw.flush();
            clinet.shutdownOutput(); // 关闭输出流

            // 释放资源
            br.close();
            isr.close();
            is.close();

            pw.close();
            os.close();

        } catch (IOException e) {
            System.out.println("服务器 run 异常:" + e.getMessage());
        } finally {
            if (clinet != null) {
                try {
                    clinet.close();
                } catch (IOException e) {
                    System.out.println("服务器 finally 异常:" + e.getMessage());
                }
            }
        }

    }

}

public static void main(String[] args) {
    System.out.println("***启动服务器***");
    TCPServer server = new TCPServer();
    server.start();
  }
}

客户端代码

public class TCPClient {

  public static void main(String[] args) {
    
    System.out.println("**客户端启动**");

    try {
        // 1.创建客户端Socket,指定服务器地址和端口
        Socket socket = new Socket("localhost", 12345);

        // 2.获取输出流,向服务端发送信息
        OutputStream os = socket.getOutputStream();
        PrintWriter pw = new PrintWriter(os);
        pw.write("我是tom,我要登录");
        pw.flush();
        socket.shutdownOutput(); // 关闭输出流

        // 3.获取输入流,并读取服务端信息
        InputStream is = socket.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String info = null;
        while ((info = br.readLine()) != null) {
            System.out.println("我是客户端,服务端说:" + info);
        }
        socket.shutdownInput(); // 关闭输入流

        // 4.关系相关资源
        br.close();
        isr.close();
        is.close();
        pw.close();
        os.close();
        socket.close();
    } catch (Exception e) {
        System.out.println("客户端异常:"+e.getMessage());
    } 
  }
}

先启动server端的代码,然后启动3次客户端代码

客户端控制台如下

**客户端启动**
我是客户端,服务端说:欢迎你登录

服务端控制台如下

***启动服务器***
服务器等待与客户端的连接...
客户端请求次数:1
我是服务器,客户端说:我是tom,我要登录
客户端请求次数:2
我是服务器,客户端说:我是tom,我要登录
客户端请求次数:3
我是服务器,客户端说:我是tom,我要登录

使用UDP

服务端代码

public class UDPServer {

  public void start() {
    try {
        // 1.创建服务端DatagramSocket
        DatagramSocket socket = new DatagramSocket(4321);

        // 2.创建数据报,用于接收客户端发送的数据
        byte[] data = new byte[1024]; // 指定接收的数据包的大小
        DatagramPacket packet = new DatagramPacket(data, data.length);

        System.out.println("服务器等待与客户端的连接...");
        int count = 0;
        while (true) {
            socket.receive(packet); // 此方法在接收到数据之前,处于阻塞状态
            count++;
            System.out.println("客户端请求次数:" + count);
            new reponseClient(socket, packet);    //放在子线程有问题
        }

    } catch (Exception e) {
        System.out.println("服务器异常:" + e.getMessage());
    }

}

// 响应客户端
private class reponseClient  {

    private DatagramSocket server;
    private DatagramPacket packet;
    public reponseClient(DatagramSocket server, DatagramPacket packet) {
        this.server = server;
        this.packet = packet;
        run();
    }

    public void run() {
        try {
            // 3.读取客户端信息
            String info = new String(packet.getData(), 0, packet.getLength(), "utf-8");
            System.out.println("我是服务器,客户端说:" + info);

            // 4.响应客户端的请求
            InetAddress address = packet.getAddress();
            int port = packet.getPort();
            String s = "欢迎你登录";
            byte[] data2 = s.getBytes("utf-8");
            // 2.创建数据报,包含响应信息
            DatagramPacket packet2 = new DatagramPacket(data2,
                    data2.length, address, port);
            // 3.响应客户端
            server.send(packet2);

        } catch (IOException e) {
            System.out.println("服务器 run 异常:" + e.getMessage());
        } finally {
            
        }

    }

}

public static void main(String[] args) {
    System.out.println("***启动服务器-UDP***");
    UDPServer server = new UDPServer();
    server.start();
  }
}

客户端代码

public class UDPClient {

  public static void main(String[] args) {
    
    System.out.println("**客户端启动-UDP**");

    try {
        //1.创建DatagramSocket对象
        DatagramSocket client=new DatagramSocket();
        
        //2.定义服务器的地址,端口号,数据
        InetAddress address=InetAddress.getByName("localhost");
        int port=4321;
        String s="我是tom,我要登录";
        byte[] data=s.getBytes("utf-8");
        
        //3.创建数据报,包含发送的数据信息
        DatagramPacket packet=new DatagramPacket(data, data.length, address, port);
    
        //4.向服务器发送数据报
        client.send(packet);
        
        

        //5.创建数据报,用于接收服务端的响应信息
        byte[] data2=new byte[1024];
        DatagramPacket packet2=new DatagramPacket(data2, data2.length);
        //6.接收服务端的响应数据
        client.receive(packet2);
        //7.读取数据
        String reply=new String(packet2.getData(),0,packet2.getLength(),"utf-8");
        System.out.println("我是客户端,服务器说:"+reply);
        //8.关闭相关资源
        client.close();
    } catch (Exception e) {
        System.out.println("客户端异常:"+e.getMessage());
    }
  }
}

同样先启动server端的代码,然后启动3次客户端代码

客户端控制台如下

**客户端启动-UDP**
我是客户端,服务器说:欢迎你登录

服务端控制台如下

***启动服务器-UDP***
服务器等待与客户端的连接...
客户端请求次数:1
我是服务器,客户端说:我是tom,我要登录
客户端请求次数:2
我是服务器,客户端说:我是tom,我要登录
客户端请求次数:3
我是服务器,客户端说:我是tom,我要登录

注意

  1. 在UDPServer代码中,启动服务放在主线程,响应客户端的代码放在子线程,第一次运行UDPClient的的时候,在服务端拿不到客户端的值。
  2. 在UDPServer代码中,启动服务放在主线程,响应客户端的代码放在主线程,一切正常。
  3. 在UDPServer代码中,启动服务放在子线程1,响应客户端的代码放在子线程2,第一次运行UDPClient的的时候,在服务端拿不到客户端的值。
  4. 在UDPServer代码中,启动服务放在子线程1,响应客户端的代码放在子线程1,一切正常。
    但在TCPServer代码中,启动服务放在主线程,响应客户端的代码放在子线程中仍然可以拿到值。

结论,UDP相关的代码一定要放在相同的线程,要么整个在主线程,要么整个在相同的子线程。

TCP在创建soket时,要求服务端和客户端的端口号要一样。
服务端的socket是ServerSocket类,客户端的socket是Socket类

UDP在创建socket时,要求服务端和客户端的端口号不一样,否则会抛地址已被占用的异常。
服务端和客户端的socket都是DatagramSocket

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

推荐阅读更多精彩内容

  • 参加在济南举办的潍坊市校长培训班,收获满满。从专家讲座到学校考察,从小组交流到茶余饭后,都在感受、吸收着来自教授、...
    武际金阅读 1,191评论 0 5
  • 柳如眉,云似发,一叶扁舟荷深处,小鱼衔玉鬓钗橫,卷荷香淡浮烟渚,石榴裙染色纱轻,转娉婷,秋意浓,尽思量,绮水愁对秋...
    淡雅浮云阅读 241评论 0 0
  • 好久不知道说些什么了,也好久没想说自己的事了,最近糟心事有,可是解决了,抱怨完了,这就是现在的自己,会...
    040a86361a12阅读 162评论 0 0
  • 学校是一个过渡的天堂,有无数的美好值得憧憬,我们从不忘怀的有好好学习,谈一场青春刻骨铭心的恋爱,拿一次奖学金,去一...
    阿猫先森阅读 658评论 1 1
  • 一月份的最后一天了。 第一次舞台看不完就难受的要命。
    水草肃Gloria阅读 92评论 0 0