java Nio使用NioSocket客户端与服务端交互实现方式

NioSocket 客户端与服务端交互实现

java Nio是jdk1.4新增的io方式—–nio(new IO),这种方式在目前来说算不算new,更合适的解释应该是non-block IO。

non-block是相对于传统的io方式来讲的。传统的Io方式是阻塞的,我们拿网络io来举例,传统的io模型如下:

服务端主线程负责不断地server.accept(),如果没有客户端请求主线程就会阻塞,当客户端请求时,主线程会通过线程池创建一个新的线程执行。

简单解释就是一个线程负责一个客户端的socket,当客户端因网络等原因传递速度慢的时候,服务端对应的客户端的线程就会等待,很浪费资源。

同时线程过少的话会影响服务的吞吐量,而线程过多的话由于上下文切换等原因会导致效率十分低下,传统的io方式并不适合如今的网络流量。

Nio的模型如下:

nio相比传统的io模型,最大的特点是优化了线程的使用。

nio通过selector可以使用一个线程去管理多个socket句柄,说是管理也不太合适,nio是采用的事件驱动模型,selector负责的是监控各个连接句柄的状态,不是去轮询每个句柄,而是在数据就绪后,将消息通知给selector,而具体的socket句柄管理则是采用多路复用的模型,交由操作系统来完成。

selector充当的是一个消息的监听者,负责监听channel在其注册的事件,这样就可以通过一个线程完成了大量连接的管理,当注册的事件发生后,再调用相应线程进行处理。

这样就不需要为每个连接都使用一个线程去维持长连接,减少了长连接的开销,同时减少了上下文的切换提高了系统的吞吐量。

java Nio的组成

java Nio主要由三个核心部分组成:

- Buffer
- Channel
- Selector

所有的io的Nio都是从一个channel开始的,Channel有点类似于流,但是和流不同的是,channel是可以双向读写的。Channel有几种类型,主要包含文件io操作和网络io:

- FileChannel (文件io)
- DatagramChannel (udp数据报)
- SocketChannel (tcp客户端)
- ServerSocketChannel (tcp服务端)

Buffer是一个中间缓存区,数据可以从channel读取到buffer,也可以从buffer写到channel中,在java中,传统方式与io的交互,需要将数据从堆内存读取到直接内存中,然后交由c语言来调用系统服务完成io的交互。

而使用Buffer可以直接在直接内存中开辟内存区域,减少了io复制的操作,从而提高了io操作的效率。

#基本数据类型的buffer
- ByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
#文件内存映射buffer
- MappedByteBuffer
#直接内存区buffer
- DirectBuffer

Selector允许单个线程处理多个channel,可以将多个channel教给selector管理,并注册相应的事件,而selector则采用事件驱动的方式,当注册的事件就绪后,调用相应的相应的线程处理该时间,不用使用线程去维持长连接,减少了线程的开销。

Selector通过静态工厂的open方法建立,然后通过channel的register注册到Channel上。

注册后通过select方法等待请求,select请求有long类型参数,代表等待时间,如果等待时间内接受到操作请求,则返回可以操作请求的数量,否则超时往下走。

传入参数为零或者无参方法,则会采用阻塞模式知道有相应请求。

收到请求后调用selectedKeys返回SelectionKey的集合。

SelectionKey保存了处理当前请求的Channel和Selector,并且提供了不同的操作类型。

SelectionKey的操作有四种:

- SelectionKey.OP_CONNECT
- SelectionKey.OP_ACCEPT
- SelectionKey.OP_READ
- SelectionKey.OP_WRITE

下面为一个客户端与服务端实用NioSocket交互的简单例子:

//对selectionKey事件的处理
/**
 * description:
 *
 * @author wkGui
 */
interface ServerHandlerBs {
    void handleAccept(SelectionKey selectionKey) throws IOException;
    String handleRead(SelectionKey selectionKey) throws IOException;
}
/**
 * description:
 *
 * @author wkGui
 */
public class ServerHandlerImpl implements ServerHandlerBs {
    private int bufferSize = 1024;
    private String localCharset = "UTF-8";
    public ServerHandlerImpl() {
    }
    public ServerHandlerImpl(int bufferSize) {
        this(bufferSize, null);
    }
    public ServerHandlerImpl(String localCharset) {
        this(-1, localCharset);
    }
    public ServerHandlerImpl(int bufferSize, String localCharset) {
        this.bufferSize = bufferSize > 0 ? bufferSize : this.bufferSize;
        this.localCharset = localCharset == null ? this.localCharset : localCharset;
    }
    @Override
    public void handleAccept(SelectionKey selectionKey) throws IOException {
        //获取channel
        SocketChannel socketChannel = ((ServerSocketChannel) selectionKey.channel()).accept();
        //非阻塞
        socketChannel.configureBlocking(false);
        //注册selector
        socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
        System.out.println("建立请求......");
    }
    @Override
    public String handleRead(SelectionKey selectionKey) throws IOException {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
        String receivedStr = "";
        if (socketChannel.read(buffer) == -1) {
            //没读到内容关闭
            socketChannel.shutdownOutput();
            socketChannel.shutdownInput();
            socketChannel.close();
            System.out.println("连接断开......");
        } else {
            //将channel改为读取状态
            buffer.flip();
            //按照编码读取数据
            receivedStr = Charset.forName(localCharset).newDecoder().decode(buffer).toString();
            buffer.clear();
            //返回数据给客户端
            buffer = buffer.put(("received string : " + receivedStr).getBytes(localCharset));
            //读取模式
            buffer.flip();
            socketChannel.write(buffer);
            //注册selector 继续读取数据
            socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
        }
        return receivedStr;
    }
}
//服务端server类
/**
 * description:
 *
 * @author wkGui
 */
public class NioSocketServer {
    private volatile byte flag = 1;
    public void setFlag(byte flag) {
        this.flag = flag;
    }
    public void start() {
        //创建serverSocketChannel,监听8888端口
        try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
            serverSocketChannel.socket().bind(new InetSocketAddress(8888));
            //设置为非阻塞模式
            serverSocketChannel.configureBlocking(false);
            //为serverChannel注册selector
            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("服务端开始工作:");
            //创建消息处理器
            ServerHandlerBs handler = new ServerHandlerImpl(1024);
            while (flag == 1) {
                selector.select();
                System.out.println("开始处理请求 : ");
                //获取selectionKeys并处理
                Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    try {
                        //连接请求
                        if (key.isAcceptable()) {
                            handler.handleAccept(key);
                        }
                        //读请求
                        if (key.isReadable()) {
                            System.out.println(handler.handleRead(key));
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    //处理完后移除当前使用的key
                    keyIterator.remove();
                }
                System.out.println("完成请求处理。");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//server端启动类
/**
 * description:
 *
 * @author wkGui
 */
public class ServerMain {
    public static void main(String[] args) {
        NioSocketServer server = new NioSocketServer();
        new Thread(() -> {
            try {
                Thread.sleep(10*60*1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                server.setFlag((byte) 0);
            }
        }).start();
        server.start();
    }
}
//客户端client类
/**
 * description:
 *
 * @author wkGui
 */
public class NioSocketClient {
    public void start() {
        try (SocketChannel socketChannel = SocketChannel.open()) {
            //连接服务端socket
            SocketAddress socketAddress = new InetSocketAddress("localhost", 8888);
            socketChannel.connect(socketAddress);
            int sendCount = 0;
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            //这里最好使用selector处理   这里只是为了写的简单
            while (sendCount < 10) {
                buffer.clear();
                //向服务端发送消息
                buffer.put(("current time : " + System.currentTimeMillis()).getBytes());
                //读取模式
                buffer.flip();
                socketChannel.write(buffer);
                buffer.clear();
                //从服务端读取消息
                int readLenth = socketChannel.read(buffer);
                //读取模式
                buffer.flip();
                byte[] bytes = new byte[readLenth];
                buffer.get(bytes);
                System.out.println(new String(bytes, "UTF-8"));
                buffer.clear();
                sendCount++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//client启动类
/**
 * description:
 *
 * @author wkGui
 */
public class ClientMain {
    public static void main(String[] args) {
        new NioSocketClient().start();
    }
}

Java NIO 实现 WebSocket 协议

WebSocket协议

WebSocket是一种在单个TCP连接上进行全双工通信的协议。 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket协议相比于Http协议来说,最大的特点就是可以实现服务端主动向客户端发送消息。在WebSocket出现之前,如果客户端想实时获取服务端的消息,就需要使用AJAX轮询,查询是否有消息,这样就很消耗服务器资源和带宽。但是用WebSocket就可以实现服务端主动向客户端发送数据,并且只需要占用一个TCP连接,节省了资源和带宽。

WebSocket连接建立过程

为了建立一个WebSocket连接,客户端浏览器首先要向服务器发起一个HTTP请求,这个请求和通常的HTTP请求不同,包含了一些附加的头信息,其中附加头信息“Upgrade: WebSocket” 表明这是一个申请协议升级的HTTP请求。服务器端解析这些附加的信息头,然后生成应答消息返回给客户端,客户端和服务端的WebSocket连接就建立了。之后就可以使用WebSocket协议的格式来双向发送消息。

建立连接时发送的HTTP请求头:

返回的HTTP响应头:

在响应头中的 Sec-WebSocket-Accept 时通过Sec-WebSocket-Key构造出来的。首先在Sec-WebSocket-Key后接上一个258EAFA5-E914-47DA-95CA-C5AB0DC85B11,然后再进行SHA1摘要得到160位数据在,在使用BASE64进行编码,最后得到的就是Sec-WebSocket-Accept。

WebSocket数据发送过程

WebSocket数据发送的帧格式如下所示:

FIN - 1bit

在数据发送的过程中,可能会分片发送,FIN表示是否为最后一个分片。如果发生了分片,则1表示时最后一个分片;不能再分片的情况下,这个标志总是为1。

RSV1 RSV2 RSV3 - 1bit each

用于扩展,不使用扩展时需要为全0;非零时通信双方必须协商好扩展。这里我们用不上。

OPCODE - 4bits

用于表示所传送数据的类型,也就是payload中的数据。

数值 含义
0x0 附加数据帧
0x1 文本数据帧
0x2 二进制数据帧
0x3-0x7 保留
0x8 关闭连接帧
0x9 ping帧
0xA pong帧
0xB-0xF 保留

MASK - 1bit

用于表示payload是否被进行了掩码运算,1表示使用掩码,0表示不使用掩码。从客户端发送向服务端的数据帧必须使用掩码。

Payload length 7 bits,7+16 bits or 7+64 bits

用于表示payload的长度,有以下三种情况:

Payload length 表示的大小 payload的长度
0 - 125 Payload length 大小
126 之后的2个字节表示的无符号整数
127 之后的8个字节表示的无符号整数

Masking-key - 0 or 4 bytes

32 bit长的掩码,如果MASK为1,则帧中就存在这一个字段,在解析payload时,需要进行使用32长掩码进行异或操作,之后才能得到正确结果。

Java NIO 实现

利用Java NIO 来实现一个聊天室。部分代码如下。

NIO的常规代码:

selector.select(1000);
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> it = selectionKeys.iterator();
while (it.hasNext()) {
    SelectionKey key = it.next();
    it.remove();
    if (key.isAcceptable()) {
        handleAccept(key);
    }
    if (key.isReadable()) {
        handleRead(key);
    }
}

接受连接:

public void handleAccept(SelectionKey key) {
    ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
    SocketChannel sc;
    try {
        sc = ssc.accept();
        sc.configureBlocking(false);
        sc.register(selector, SelectionKey.OP_READ);
        System.out.println(String.format("[server] -- client %s connected.", sc.getRemoteAddress().toString()));
    } catch (IOException e) {
        System.out.println(String.format("[server] -- error occur when accept: %s.", e.getMessage()));
        key.cancel();
    }
}

读取通道中的数据:

public void handleRead(SelectionKey key) {
    SocketChannel sc = (SocketChannel) key.channel();
    Client client = (Client) key.attachment();
    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
    // 如果是第一次连接进来,就需要创建一个客户端对象,存储起来
    if (client == null) {
        client = new Client(sc);
        clients.add(client);
        key.attach(client);
        byteBuffer.clear();
        // 如果连接还没有建立,就是要HTTP建立连接
        try {
            sc.read(byteBuffer);
            byteBuffer.flip();
            String response = WebSocketHandler.getResponse(new String(byteBuffer.array()));
            byteBuffer.clear();
            byteBuffer.put(response.getBytes());
            byteBuffer.flip();
            while (byteBuffer.hasRemaining()) {
                sc.write(byteBuffer);
            }
        } catch (IOException e) {
            System.out.println(String.format("[server] -- error occur when read: %s.", e.getMessage()));
        }
        String message = "[系统消息] " + client.toString() + " 加入了群聊";
        broadcast(message.getBytes(), client);
    }
    byteBuffer.clear();
    int read = 0;
    try {
        read = sc.read(byteBuffer);
        if (read > 0) {
            byteBuffer.flip();
            int opcode = byteBuffer.get() & 0x0f;
            // 8表示客户端关闭了连接
            if (opcode == 8) {
                System.out.println(String.format("[server] -- client %s connection close.", sc.getRemoteAddress()));
                clients.remove(client);
                String message = "[系统消息] " + client.toString() + " 退出了群聊";
                broadcast(message.getBytes(), client);
                sc.close();
                key.cancel();
                return;
            }
   // 只考虑了最简单的payload长度情况。
            int len = byteBuffer.get();
            len &= 0x7f;
            byte[] mask = new byte[4];
            byteBuffer.get(mask);
            byte[] payload = new byte[len];
            byteBuffer.get(payload);
            for (int i = 0; i < payload.length; i++) {
                payload[i] ^= mask[i % 4];
            }
            System.out.println(String
                    .format("[server] -- client: [%s], send: [%s].", client.toString(), new String(payload)));
            String message = String.format("[%s]: %s", client.toString(), new String(payload));
            broadcast(message.getBytes(), client);
        } else if (read == -1) {
            System.out.println(String.format("[server] -- client %s connection close.", sc.getRemoteAddress()));
            clients.remove(client);
            String message = "[系统消息] " + client.toString() + " 退出了群聊";
            broadcast(message.getBytes(), client);
            sc.close();
            key.cancel();
        }
    } catch (IOException e) {
        System.out.println(String.format("[server] -- error occur when read: %s.", e.getMessage()));
    }
}

使用HTTP建立WebSocket连接。

public class WebSocketHandler {
    private static String APPEND_STRING = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    static class Header {
        private Map<String, String> properties = new HashMap<>();
        public String get(String key) {
            return properties.get(key);
        }
    }
    private WebSocketHandler() {}
    private static Header phrase(String request) {
        Header header = new Header();
        String[] pros = request.split("\r\n");
        for (String pro : pros) {
            if (pro.contains(":")) {
                int index = pro.indexOf(":");
                String key = pro.substring(0, index).trim();
                String value = pro.substring(index + 1).trim();
                header.properties.put(key, value);
            }
        }
        return header;
    }
    public static String getResponse(String request) {
        Header header = phrase(request);
        String acceptKey = header.get("Sec-WebSocket-Key") + APPEND_STRING;
        MessageDigest sha1;
        try {
            sha1 = MessageDigest.getInstance("sha1");
            sha1.update(acceptKey.getBytes());
            acceptKey = new String(Base64.getEncoder().encode(sha1.digest()));
        } catch (NoSuchAlgorithmException e) {
            System.out.println("fail to encode " + e.getMessage());
            return null;
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("HTTP/1.1 101 Switching Protocols\r\n").append("Upgrade: websocket\r\n")
                     .append("Connection: Upgrade\r\n").append("Sec-WebSocket-Accept: " + acceptKey + "\r\n")
                     .append("\r\n");
        return stringBuilder.toString();
    }
}

客户端对象

/**
 * @author XinHui Chen
 * @date 2020/2/8 19:20
 */
public class Client {
    private SocketChannel socketChannel = null;
    private String id = null;
    public SocketChannel getSocketChannel() {
        return socketChannel;
    }
    public String getId() {
        return id;
    }
    Client(SocketChannel socketChannel) {
        this.socketChannel = socketChannel;
        this.id = UUID.randomUUID().toString();
    }
    @Override
    public String toString() {
        try {
            return id + " " + socketChannel.getRemoteAddress().toString();
        } catch (IOException e) {
            System.out.println(e.getMessage());
            return null;
        }
    }
}

结果

使用网页和控制台与服务端建立WebSocket连接,发送数据。两个都能成功显示。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 教你怎么用java实现客户端与服务器一问一答

    运行效果 开启多个客户端 服务端效果: 客户端效果: 当一个客户端断开连接: 代码 因为代码中有注释,我就直接贴上来了 服务端: package com.dayrain.server; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.ByteBuffer; import java.nio.channels.*; import j

  • Java使用NioSocket手动实现HTTP服务器

    NioSocket简单复习 重要概念 NioSocket里面的三个重要概念:Buffer.Channel.Selector Buffer为要传输的数据 Channel为传输数据的通道 Selector为通道的分配调度者 使用步骤 使用NioSocket实现通信大概如以下步骤: ServerSocketChannel可以通过configureBlocking方法来设置是否采用阻塞模式,设置为false后就可以调用register注册Selector,阻塞模式下不可以用Selector. 注册后,S

  • java 中模拟TCP传输的客户端和服务端实例详解

    一.创建TCP传输的客户端 1.建立TCP客户端的Socket服务,使用的是Socket对象,建议该对象一创建就明确目的地,即要连接的主机: 2.如果连接建立成功,说明数据传输通道已建立,该通道就是Socket流,是底层建立好的,既然是流,说着这里既有输入流,又有输出流,想要输入流或者输出流对象,可以通过Socket来获取,可以通过getOutputStream()和getInputStream()来获取: 3.使用输出流,将数据写出: 4.关闭Socket服务. import java.io.

  • Spring Boot集成netty实现客户端服务端交互示例详解

    前言 Netty 是一个高性能的 NIO 网络框架,本文主要给大家介绍了关于SpringBoot集成netty实现客户端服务端交互的相关内容,下面来一起看看详细的介绍吧 看了好几天的netty实战,慢慢摸索,虽然还没有摸着很多门道,但今天还是把之前想加入到项目里的 一些想法实现了,算是有点信心了吧(讲真netty对初学者还真的不是很友好......) 首先,当然是在SpringBoot项目里添加netty的依赖了,注意不要用netty5的依赖,因为已经废弃了 <!--netty--> <

  • Java使用NIO包实现Socket通信的实例代码

    前面几篇文章介绍了使用java.io和java.net类库实现的Socket通信,下面介绍一下使用java.nio类库实现的Socket. java.nio包是Java在1.4之后增加的,用来提高I/O操作的效率.在nio包中主要包括以下几个类或接口: Buffer:缓冲区,用来临时存放输入或输出数据. Charset:用来把Unicode字符编码和其它字符编码互转. Channel:数据传输通道,用来把Buffer中的数据写入到数据源,或者把数据源中的数据读入到Buffer. Selector

  • java Nio使用NioSocket客户端与服务端交互实现方式

    NioSocket 客户端与服务端交互实现 java Nio是jdk1.4新增的io方式-–nio(new IO),这种方式在目前来说算不算new,更合适的解释应该是non-block IO. non-block是相对于传统的io方式来讲的.传统的Io方式是阻塞的,我们拿网络io来举例,传统的io模型如下: 服务端主线程负责不断地server.accept(),如果没有客户端请求主线程就会阻塞,当客户端请求时,主线程会通过线程池创建一个新的线程执行. 简单解释就是一个线程负责一个客户端的sock

  • Android客户端与服务端交互

    本文和大家一起了解了一下android客户端与服务端是怎样交互的,具体内容如下 1.后台使用简单的servlet,支持GET或POST.这个servlet最终返回给前台一个字符串flag,值是true或false,表示登录是否成功. servlet使用之前需要配置,主义servlet的servlet-name要和servlet-mapping的servlet-name一致,否则找不到路径 我是在myEclipse上创建的一个web service 项目,然后部署到tomcat服务器上以便andr

  • Java网络编程之简单的服务端客户端应用实例

    本文实例讲述了Java网络编程之简单的服务端客户端应用.分享给大家供大家参考.具体如下: 在Java中,我们使用java.net.Socket及其相关类来完成有关网络的相关功能.Socket类非常简单易用,因为Java技术隐藏了建立网络连接和通过连接发送数据的复杂过程.下面所说的内容只适用于TCP协议. 一.连接到服务器 我们可以使用Socket类的构造函数来打开一个套接字,如 Socket sk = new Socket("210.0.235.14",13); 其中,210.0.23

  • Java 客户端向服务端上传mp3文件数据的实例代码

    客户端: package cn.itcast.uploadpicture.demo; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.net.Socket; import java.net.UnknownHostExce

  • Java基于socket实现的客户端和服务端通信功能完整实例

    本文实例讲述了Java基于socket实现的客户端和服务端通信功能.分享给大家供大家参考,具体如下: 以下代码参考马士兵的聊天项目,先运行ChatServer.java实现端口监听,然后再运行ChatClient.java 客户端实例 ChatClient.java package socketDemo; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; public class Ch

  • SpringBoot整合WebSocket的客户端和服务端的实现代码

    目录 一.项目中服务端的创建 二.java充当客户端链接ws 1.ws客户端的配置 2.配置信息需要在项目启动的时候去启用和链接ws服务 3.接收服务端推送的消息进行权限过滤demo 4.ws客户端推送消息,推送消息和上面服务端类似. 本文是项目中使用了websocket进行一些数据的推送,对比项目做了一个demo,ws的相关问题不做细数,仅做一下记录. 此demo针对ws的搭建主要逻辑背景是一个服务端B:通讯层 产生消息推送出去,另外一个项目A充当客户端和服务端,A的客户端:是接收通讯层去无差

  • Python警察与小偷的实现之一客户端与服务端通信实例

    本文实例讲述了Python警察与小偷的实现之一客户端与服务端通信,分享给大家供大家参考.具体方法分析如下: 该实例来源于ISCC 2012 破解关第四题 目的是通过逆向police,实现一个thief,能够与police进行通信 实际上就是一个RSA加密通信的例子,我们通过自己编写客户端和服务端来实现上面的thief和police的功能. 要通信,这们这次先通过python写出可以进行网络连接的客户端与服务端. 服务端代码如下: #!/usr/bin/env python import Sock

  • python Socket之客户端和服务端握手详解

    简单的学习下利用socket来建立客户端和服务端之间的连接并且发送数据 1. 客户端socketClient.py代码 import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立连接: s.connect(('127.0.0.1', 9999)) # 接收欢迎消息: print(s.recv(1024).decode('utf-8')) for data in [b'Michael', b'Tracy', b'

  • 用PHP的socket实现客户端到服务端的通信实例详解

    一.server.php服务端: <?php error_reporting(E_ALL); set_time_limit(0); ob_implicit_flush(); //本地IP $address = 'localhost'; //设置用111端口进行通信 $port = 111; //创建SOCKET if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) { echo "socket创建失败原因 &q

随机推荐