zoukankan      html  css  js  c++  java
  • Java多线程 Socket使用

    点我跳过黑哥的卑鄙广告行为,进入正文。

    Java多线程系列更新中~

      正式篇:

    1. Java多线程(一) 什么是线程
    2. Java多线程(二)关于多线程的CPU密集型和IO密集型这件事
    3. Java多线程(三)如何创建线程
    4. Java多线程(四)java中的Sleep方法
    5. Java多线程(五)线程的生命周期

      番外篇(神TM番外篇):

    1. Java 过一下基础
    2. 转载:java中Thread.sleep()函数使用
    3. Java多线程 Socket使用

    Socket是客户端和服务器端交流的端点。通过它可以实现客户端和服务器端的通信。顺着这篇文章操作下来,你应该会对Socket编程有比较系统的了解。注意,跟着敲代码,有什么不懂而我又没提到的地方,随时百度,不要积累误差。

    客户端编程

    Socket是有连接的,所以双方建立通信,需要知道彼此的网络位置(IP和端口)。

    创建Socket对象:

    Socket socket = new Socket("127.0.0.1",8852);
    • 第一个参数:服务器的IP地址(这里用的是本机地址)
    • 第二个参数:TCP端口号,其中0~1023是系统保留端口。

    为什么需要端口号?例如你想要去找你的暗恋对象告白,你知道她的学校地址(IP地址),但是一个学校不会只有你暗恋对象一个人(一个主机不会只进行一个任务),你需要知道她的宿舍号(端口号),这样才能方便告白。

    使用本机既做客户端,又做服务器是个什么情况?就是你和你暗恋对象在同一个学校,这没什么区别,你仍然需要她的宿舍号(端口号)才能找到她告白(客户端和服务前通信)。

    初始版本代码

    public class MyClient {
        public static void main(String[] args) throws Exception{
        Socket socket = new Socket("127.0.0.1",8852);
        DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
        dataOutputStream.writeUTF("Hello socket");
        socket.close();
        }
    }

    注意别忘了抛出异常,这里只是个演示作用,直接throws Exception了。这里你直接运行肯定是不能建立连接的,因为服务器端还没写。

    这里,假如你知道服务器监听的是8852端口,你创建了一个socket来和它进行通信。socket.getOutputStream()得到这个socket的输出流,当你调用writeUTF()方法时,便会向其中写一个字符串。

    典型三段式要牢记:打开、通信、关闭。

    服务器端编程

    注意了注意了,要开始造女票了。

    初始版本代码

    import java.io.DataInputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class MyServer {
        public static void main(String[] args) throws Exception{
            ServerSocket serverSocket = new ServerSocket(8852);
            System.out.println("Server 等待接收数据~");
            Socket socket = serverSocket.accept();
            DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
            String string = dataInputStream.readUTF();
            System.out.println(string);
            System.out.println("Server 接收数据完毕,拜拜了您~");
            socket.close();
            serverSocket.close();
        }
    }    

    这里服务器端用到了ServerSocket,负责接收客户端的连接请求。你的暗恋对象可能有好多人要向她告白,一个Socket自然无法处理。通过ServerSocket的accept方法从连接请求队列中取出一个进行连接。那这个ServerSocket就是你暗恋对象的室友,帮助她管理诸多“告白”。

    这里只是把服务器端接收到的数据打印了一下便关闭了。至此,一个简单的服务器-客户端通信便建立了。但是这个服务器只能处理一个连接便关闭了,我们可以改进一下。

    往下看之前请确保你大致理解了上述过程,最好自己敲一下代码

    到这里你可能会想,只处理一个就关闭了,那我加个while循环,让它一直运行怎么样?

    听着还可以,那我们来试验一下(下面只是分析一下,不用跟着敲)。

    将服务器端代码更改为:

    while(true)
    {
      Socket socket = serverSocket.accept();
      DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
      String string = dataInputStream.readUTF();
      System.out.println(string);
      socket.close();
      serverSocket.close();
    }     

    这个会出现什么问题?客户端正连着呢,啪,你服务器给人家断开了,而且accept()接受的是socket请求,所以这种情况,除非客户端再连一次,否则二者的通信就断了。

    你可能会说,那我把Socket移到外面呢?

    其实吧,这个仔细理一下就会明白,如果放到外面的话,只要你想接收多个socket,就要把

    Socket socket = serverSocket.accept();放到while循环中,但是你只要把它放到while循环中,它就只能和一个socket进行通信。这里有兴趣可以再查阅一下资料,下面直接进入线程阶段。

    服务器端线程代码

    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class MyServer {
    
        public static void main(String[] args) throws Exception{
            ServerSocket serverSocket = new ServerSocket(8852);
            System.out.println("Server 等待接收数据~");
            while(true) {
                Socket socket = serverSocket.accept();
           //这里来一个连接请求就让deal去处理,自己在这里等下一个连接请求 deal(socket); } }
    public static void deal(Socket client){
         //这里创建了一个新的线程
    new Thread(new Runnable() { @Override public void run() { DataInputStream dataInputStream=null; DataOutputStream dataOutputStream = null; String receiveFromClient=""; try { dataInputStream = new DataInputStream(client.getInputStream()); dataOutputStream = new DataOutputStream(client.getOutputStream()); //只是这个线程中一直while循环,不影响其他的线程。 while(true) { receiveFromClient = dataInputStream.readUTF(); System.out.println("receive: "+receiveFromClient); if(receiveFromClient.equals("bye")) { dataOutputStream.writeUTF("终于厌倦我了吗?客户端都是大猪蹄子!!"); dataOutputStream.flush(); break; } else { dataOutputStream.writeUTF("你TM给我发 "+receiveFromClient+" 干什么?"); dataOutputStream.flush(); } } }catch (Exception e) { e.printStackTrace(); }finally { try { dataInputStream.close(); dataOutputStream.close(); client.close(); } catch (IOException e) { e.printStackTrace(); } } } }).start(); } }

    客户端代码:

    import java.io.BufferedReader;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.InputStreamReader;
    import java.net.Socket;
    
    public class MyClient {
        public static void main(String[] args) throws Exception{
            Socket socket = new Socket("127.0.0.1",8852);
            DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
            DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
            BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
            String string;
            while(true)
            {
                string=bReader.readLine();
                dataOutputStream.writeUTF(string);
                System.out.println(dataInputStream.readUTF());
                dataOutputStream.flush();
                if(string.equals("bye"))
                    break;
            }
            socket.close();
        }
    }

    结果展示:

    服务器端:

    客户端:

  • 相关阅读:
    Redis应用----消息传递
    Memcache存储机制与指令汇总
    文本挖掘预处理之向量化与Hash Trick
    证书(Certificate)与描述文件(Provisioning Profiles)
    IOS使用命令行打包
    IOS使用xcode编译代码
    IOS使用SourceTree
    docker修改docker0 mtu
    linux开机自启动
    设计模式
  • 原文地址:https://www.cnblogs.com/hqinglau/p/10055458.html
Copyright © 2011-2022 走看看