TCP/UDP/LOCAL Socket C++的实现

前言

         本篇文章主要是记录了Native层Socket的实现,包括TCP、UDP和LOCAL。一般来说,我们使用Socket通信都是通过调用Java层的Api来实现,而Java层Api最终也会走到Native层来具体实现,而且其实不管是http、tcp、udp还是bluetooth抑或是WifiDirect都是在Socket的基础上封装而来,只不过协议不同而已。虽然在开发中通过调用Java层Api可以很方便的使用Socket,但是一些特殊情况下还是得用底层Socket的实现,比如需要写一些安全性较高的网络连接的时候,就需要自己在Native层实现网络的请求。

实现

// JNI
#include <jni.h>

// NULL
#include <stdio.h>

// va_list, vsnprintf
#include <stdarg.h>

// errno
#include <errno.h>

// strerror_r, memset
#include <string.h>

// socket, bind, getsockname, listen, accept, recv, send, connect
#include <sys/types.h>
#include <sys/socket.h>

// sockaddr_un
#include <sys/un.h>

// htons, sockaddr_in
#include <netinet/in.h>

// inet_ntop
#include <arpa/inet.h>

// close, unlink
#include <unistd.h>

// offsetof
#include <stddef.h>

// Max log message length
#define MAX_LOG_MESSAGE_LENGTH 256

// Max data buffer size
#define MAX_BUFFER_SIZE 80

/**
 * Logs the given message to the application.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param format message format and arguments.
 */
static void LogMessage(
        JNIEnv *env,
        jobject obj,
        const char *format,
        ...) {
    // Cached log method ID
    static jmethodID methodID = NULL;

    // If method ID is not cached
    if (NULL == methodID) {
        // Get class from object
        jclass clazz = env->GetObjectClass(obj);

        // Get the method ID for the given method
        methodID = env->GetMethodID(clazz, "logMessage",
                                    "(Ljava/lang/String;)V");

        // Release the class reference
        env->DeleteLocalRef(clazz);
    }

    // If method is found
    if (NULL != methodID) {
        // Format the log message
        char buffer[MAX_LOG_MESSAGE_LENGTH];

        va_list ap;
        va_start(ap, format);
        vsnprintf(buffer, MAX_LOG_MESSAGE_LENGTH, format, ap);
        va_end(ap);

        // Convert the buffer to a Java string
        jstring message = env->NewStringUTF(buffer);

        // If string is properly constructed
        if (NULL != message) {
            // Log message
            env->CallVoidMethod(obj, methodID, message);

            // Release the message reference
            env->DeleteLocalRef(message);
        }
    }
}

/**
 * Throws a new exception using the given exception class
 * and exception message.
 *
 * @param env JNIEnv interface.
 * @param className class name.
 * @param message exception message.
 */
static void ThrowException(
        JNIEnv *env,
        const char *className,
        const char *message) {
    // Get the exception class
    jclass clazz = env->FindClass(className);

    // If exception class is found
    if (NULL != clazz) {
        // Throw exception
        env->ThrowNew(clazz, message);

        // Release local class reference
        env->DeleteLocalRef(clazz);
    }
}

/**
 * Throws a new exception using the given exception class
 * and error message based on the error number.
 *
 * @param env JNIEnv interface.
 * @param className class name.
 * @param errnum error number.
 */
static void ThrowErrnoException(
        JNIEnv *env,
        const char *className,
        int errnum) {
    char buffer[MAX_LOG_MESSAGE_LENGTH];

    // Get message for the error number
    if (-1 == strerror_r(errnum, buffer, MAX_LOG_MESSAGE_LENGTH)) {
        strerror_r(errno, buffer, MAX_LOG_MESSAGE_LENGTH);
    }

    // Throw exception
    ThrowException(env, className, buffer);
}

/**
 * Constructs a new TCP socket.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @return socket descriptor.
 * @throws IOException
 */
static int NewTcpSocket(JNIEnv *env, jobject obj) {
    // Construct socket
    LogMessage(env, obj, "Constructing a new TCP socket...");
    int tcpSocket = socket(PF_INET, SOCK_STREAM, 0);

    // Check if socket is properly constructed
    if (-1 == tcpSocket) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    }

    return tcpSocket;
}

/**
 * Binds socket to a port number.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @param port port number or zero for random port.
 * @throws IOException
 */
static void BindSocketToPort(
        JNIEnv *env,
        jobject obj,
        int sd,
        unsigned short port) {
    struct sockaddr_in address;

    // Address to bind socket
    memset(&address, 0, sizeof(address));
    address.sin_family = PF_INET;

    // Bind to all addresses
    address.sin_addr.s_addr = htonl(INADDR_ANY);

    // Convert port to network byte order
    address.sin_port = htons(port);

    // Bind socket
    LogMessage(env, obj, "Binding to port %hu.", port);
    if (-1 == bind(sd, (struct sockaddr *) &address, sizeof(address))) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    }
}

/**
 * Gets the port number socket is currently binded.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @return port number.
 * @throws IOException
 */
static unsigned short GetSocketPort(
        JNIEnv *env,
        jobject obj,
        int sd) {
    unsigned short port = 0;

    struct sockaddr_in address;
    socklen_t addressLength = sizeof(address);

    // Get the socket address
    if (-1 == getsockname(sd, (struct sockaddr *) &address, &addressLength)) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    } else {
        // Convert port to host byte order
        port = ntohs(address.sin_port);

        LogMessage(env, obj, "Binded to random port %hu.", port);
    }

    return port;
}

/**
 * Listens on given socket with the given backlog for
 * pending connections. When the backlog is full, the
 * new connections will be rejected.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @param backlog backlog size.
 * @throws IOException
 */
static void ListenOnSocket(
        JNIEnv *env,
        jobject obj,
        int sd,
        int backlog) {
    // Listen on socket with the given backlog
    LogMessage(env, obj,
               "Listening on socket with a backlog of %d pending connections.",
               backlog);

    if (-1 == listen(sd, backlog)) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    }
}

/**
 * Logs the IP address and the port number from the
 * given address.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param message message text.
 * @param address adress instance.
 * @throws IOException
 */
static void LogAddress(
        JNIEnv *env,
        jobject obj,
        const char *message,
        const struct sockaddr_in *address) {
    char ip[INET_ADDRSTRLEN];

    // Convert the IP address to string
    if (NULL == inet_ntop(PF_INET,
                          &(address->sin_addr),
                          ip,
                          INET_ADDRSTRLEN)) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    } else {
        // Convert port to host byte order
        unsigned short port = ntohs(address->sin_port);

        // Log address
        LogMessage(env, obj, "%s %s:%hu.", message, ip, port);
    }
}

/**
 * Blocks and waits for incoming client connections on the
 * given socket.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @return client socket.
 * @throws IOException
 */
static int AcceptOnSocket(
        JNIEnv *env,
        jobject obj,
        int sd) {
    struct sockaddr_in address;
    socklen_t addressLength = sizeof(address);

    // Blocks and waits for an incoming client connection
    // and accepts it
    LogMessage(env, obj, "Waiting for a client connection...");

    int clientSocket = accept(sd,
                              (struct sockaddr *) &address,
                              &addressLength);

    // If client socket is not valid
    if (-1 == clientSocket) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    } else {
        // Log address
        LogAddress(env, obj, "Client connection from ", &address);
    }

    return clientSocket;
}

/**
 * Block and receive data from the socket into the buffer.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @param buffer data buffer.
 * @param bufferSize buffer size.
 * @return receive size.
 * @throws IOException
 */
static ssize_t ReceiveFromSocket(
        JNIEnv *env,
        jobject obj,
        int sd,
        char *buffer,
        size_t bufferSize) {
    // Block and receive data from the socket into the buffer
    LogMessage(env, obj, "Receiving from the socket...");
    ssize_t recvSize = recv(sd, buffer, bufferSize - 1, 0);

    // If receive is failed
    if (-1 == recvSize) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    } else {
        // NULL terminate the buffer to make it a string
        buffer[recvSize] = NULL;

        // If data is received
        if (recvSize > 0) {
            LogMessage(env, obj, "Received %d bytes: %s", recvSize, buffer);
        } else {
            LogMessage(env, obj, "Client disconnected.");
        }
    }

    return recvSize;
}

/**
 * Send data buffer to the socket.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @param buffer data buffer.
 * @param bufferSize buffer size.
 * @return sent size.
 * @throws IOException
 */
static ssize_t SendToSocket(
        JNIEnv *env,
        jobject obj,
        int sd,
        const char *buffer,
        size_t bufferSize) {
    // Send data buffer to the socket
    LogMessage(env, obj, "Sending to the socket...");
    ssize_t sentSize = send(sd, buffer, bufferSize, 0);

    // If send is failed
    if (-1 == sentSize) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    } else {
        if (sentSize > 0) {
            LogMessage(env, obj, "Sent %d bytes: %s", sentSize, buffer);
        } else {
            LogMessage(env, obj, "Client disconnected.");
        }
    }

    return sentSize;
}

/**
 * Connects to given IP address and given port.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @param ip IP address.
 * @param port port number.
 * @throws IOException
 */
static void ConnectToAddress(
        JNIEnv *env,
        jobject obj,
        int sd,
        const char *ip,
        unsigned short port) {
    // Connecting to given IP address and given port
    LogMessage(env, obj, "Connecting to %s:%uh...", ip, port);

    struct sockaddr_in address;

    memset(&address, 0, sizeof(address));
    address.sin_family = PF_INET;

    // Convert IP address string to Internet address
    if (0 == inet_aton(ip, &(address.sin_addr))) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    } else {
        // Convert port to network byte order
        address.sin_port = htons(port);

        // Connect to address
        if (-1 == connect(sd, (const sockaddr *) &address, sizeof(address))) {
            // Throw an exception with error number
            ThrowErrnoException(env, "java/io/IOException", errno);
        } else {
            LogMessage(env, obj, "Connected.");
        }
    }
}

void Java_com_apress_echo_EchoClientActivity_nativeStartTcpClient(
        JNIEnv *env,
        jobject obj,
        jstring ip,
        jint port,
        jstring message) {
    // Construct a new TCP socket.
    int clientSocket = NewTcpSocket(env, obj);
    if (NULL == env->ExceptionOccurred()) {
        // Get IP address as C string
        const char *ipAddress = env->GetStringUTFChars(ip, NULL);
        if (NULL == ipAddress)
            goto exit;

        // Connect to IP address and port
        ConnectToAddress(env, obj, clientSocket, ipAddress,
                         (unsigned short) port);

        // Release the IP address
        env->ReleaseStringUTFChars(ip, ipAddress);

        // If connection was successful
        if (NULL != env->ExceptionOccurred())
            goto exit;

        // Get message as C string
        const char *messageText = env->GetStringUTFChars(message, NULL);
        if (NULL == messageText)
            goto exit;

        // Get the message size
        jsize messageSize = env->GetStringUTFLength(message);

        // Send message to socket
        SendToSocket(env, obj, clientSocket, messageText, messageSize);

        // Release the message text
        env->ReleaseStringUTFChars(message, messageText);

        // If send was not successful
        if (NULL != env->ExceptionOccurred())
            goto exit;

        char buffer[MAX_BUFFER_SIZE];

        // Receive from the socket
        ReceiveFromSocket(env, obj, clientSocket, buffer, MAX_BUFFER_SIZE);
    }

    exit:
    if (clientSocket > 0) {
        close(clientSocket);
    }
}

void Java_com_apress_echo_EchoServerActivity_nativeStartTcpServer(
        JNIEnv *env,
        jobject obj,
        jint port) {
    // Construct a new TCP socket.
    int serverSocket = NewTcpSocket(env, obj);
    if (NULL == env->ExceptionOccurred()) {
        // Bind socket to a port number
        BindSocketToPort(env, obj, serverSocket, (unsigned short) port);
        if (NULL != env->ExceptionOccurred())
            goto exit;

        // If random port number is requested
        if (0 == port) {
            // Get the port number socket is currently binded
            GetSocketPort(env, obj, serverSocket);
            if (NULL != env->ExceptionOccurred())
                goto exit;
        }

        // Listen on socket with a backlog of 4 pending connections
        ListenOnSocket(env, obj, serverSocket, 4);
        if (NULL != env->ExceptionOccurred())
            goto exit;

        // Accept a client connection on socket
        int clientSocket = AcceptOnSocket(env, obj, serverSocket);
        if (NULL != env->ExceptionOccurred())
            goto exit;

        char buffer[MAX_BUFFER_SIZE];
        ssize_t recvSize;
        ssize_t sentSize;

        // Receive and send back the data
        while (1) {
            // Receive from the socket
            recvSize = ReceiveFromSocket(env, obj, clientSocket,
                                         buffer, MAX_BUFFER_SIZE);

            if ((0 == recvSize) || (NULL != env->ExceptionOccurred()))
                break;

            // Send to the socket
            sentSize = SendToSocket(env, obj, clientSocket,
                                    buffer, (size_t) recvSize);

            if ((0 == sentSize) || (NULL != env->ExceptionOccurred()))
                break;
        }

        // Close the client socket
        close(clientSocket);
    }

    exit:
    if (serverSocket > 0) {
        close(serverSocket);
    }
}

/**
 * Constructs a new UDP socket.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @return socket descriptor.
 * @throws IOException
 */
static int NewUdpSocket(JNIEnv *env, jobject obj) {
    // Construct socket
    LogMessage(env, obj, "Constructing a new UDP socket...");
    int udpSocket = socket(PF_INET, SOCK_DGRAM, 0);

    // Check if socket is properly constructed
    if (-1 == udpSocket) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    }

    return udpSocket;
}

/**
 * Block and receive datagram from the socket into
 * the buffer, and populate the client address.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @param address client address.
 * @param buffer data buffer.
 * @param bufferSize buffer size.
 * @return receive size.
 * @throws IOException
 */
static ssize_t ReceiveDatagramFromSocket(
        JNIEnv *env,
        jobject obj,
        int sd,
        struct sockaddr_in *address,
        char *buffer,
        size_t bufferSize) {
    socklen_t addressLength = sizeof(struct sockaddr_in);

    // Receive datagram from socket
    LogMessage(env, obj, "Receiving from the socket...");
    ssize_t recvSize = recvfrom(sd, buffer, bufferSize, 0,
                                (struct sockaddr *) address,
                                &addressLength);

    // If receive is failed
    if (-1 == recvSize) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    } else {
        // Log address
        LogAddress(env, obj, "Received from", address);

        // NULL terminate the buffer to make it a string
        buffer[recvSize] = NULL;

        // If data is received
        if (recvSize > 0) {
            LogMessage(env, obj, "Received %d bytes: %s", recvSize, buffer);
        }
    }

    return recvSize;
}

/**
 * Sends datagram to the given address using the given socket.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @param address remote address.
 * @param buffer data buffer.
 * @param bufferSize buffer size.
 * @return sent size.
 * @throws IOException
 */
static ssize_t SendDatagramToSocket(
        JNIEnv *env,
        jobject obj,
        int sd,
        const struct sockaddr_in *address,
        const char *buffer,
        size_t bufferSize) {
    // Send data buffer to the socket
    LogAddress(env, obj, "Sending to", address);
    ssize_t sentSize = sendto(sd, buffer, bufferSize, 0,
                              (const sockaddr *) address,
                              sizeof(struct sockaddr_in));

    // If send is failed
    if (-1 == sentSize) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    } else if (sentSize > 0) {
        LogMessage(env, obj, "Sent %d bytes: %s", sentSize, buffer);
    }

    return sentSize;
}

void Java_com_apress_echo_EchoClientActivity_nativeStartUdpClient(
        JNIEnv *env,
        jobject obj,
        jstring ip,
        jint port,
        jstring message) {
    // Construct a new UDP socket.
    int clientSocket = NewUdpSocket(env, obj);
    if (NULL == env->ExceptionOccurred()) {
        struct sockaddr_in address;

        memset(&address, 0, sizeof(address));
        address.sin_family = PF_INET;

        // Get IP address as C string
        const char *ipAddress = env->GetStringUTFChars(ip, NULL);
        if (NULL == ipAddress)
            goto exit;

        // Convert IP address string to Internet address
        int result = inet_aton(ipAddress, &(address.sin_addr));

        // Release the IP address
        env->ReleaseStringUTFChars(ip, ipAddress);

        // If conversion is failed
        if (0 == result) {
            // Throw an exception with error number
            ThrowErrnoException(env, "java/io/IOException", errno);
            goto exit;
        }

        // Convert port to network byte order
        address.sin_port = htons(port);

        // Get message as C string
        const char *messageText = env->GetStringUTFChars(message, NULL);
        if (NULL == messageText)
            goto exit;

        // Get the message size
        jsize messageSize = env->GetStringUTFLength(message);

        // Send message to socket
        SendDatagramToSocket(env, obj, clientSocket, &address,
                             messageText, messageSize);

        // Release the message text
        env->ReleaseStringUTFChars(message, messageText);

        // If send was not successful
        if (NULL != env->ExceptionOccurred())
            goto exit;

        char buffer[MAX_BUFFER_SIZE];

        // Clear address
        memset(&address, 0, sizeof(address));

        // Receive from the socket
        ReceiveDatagramFromSocket(env, obj, clientSocket, &address,
                                  buffer, MAX_BUFFER_SIZE);
    }

    exit:
    if (clientSocket > 0) {
        close(clientSocket);
    }
}

void Java_com_apress_echo_EchoServerActivity_nativeStartUdpServer(
        JNIEnv *env,
        jobject obj,
        jint port) {
    // Construct a new UDP socket.
    int serverSocket = NewUdpSocket(env, obj);
    if (NULL == env->ExceptionOccurred()) {
        // Bind socket to a port number
        BindSocketToPort(env, obj, serverSocket, (unsigned short) port);
        if (NULL != env->ExceptionOccurred())
            goto exit;

        // If random port number is requested
        if (0 == port) {
            // Get the port number socket is currently binded
            GetSocketPort(env, obj, serverSocket);
            if (NULL != env->ExceptionOccurred())
                goto exit;
        }

        // Client address
        struct sockaddr_in address;
        memset(&address, 0, sizeof(address));

        char buffer[MAX_BUFFER_SIZE];
        ssize_t recvSize;
        ssize_t sentSize;

        // Receive from the socket
        recvSize = ReceiveDatagramFromSocket(env, obj, serverSocket,
                                             &address, buffer, MAX_BUFFER_SIZE);

        if ((0 == recvSize) || (NULL != env->ExceptionOccurred()))
            goto exit;

        // Send to the socket
        sentSize = SendDatagramToSocket(env, obj, serverSocket,
                                        &address, buffer, (size_t) recvSize);
    }

    exit:
    if (serverSocket > 0) {
        close(serverSocket);
    }
}

/**
 * Constructs a new Local UNIX socket.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @return socket descriptor.
 * @throws IOException
 */
static int NewLocalSocket(JNIEnv *env, jobject obj) {
    // Construct socket
    LogMessage(env, obj, "Constructing a new Local UNIX socket...");
    int localSocket = socket(PF_LOCAL, SOCK_STREAM, 0);

    // Check if socket is properly constructed
    if (-1 == localSocket) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    }

    return localSocket;
}

/**
 * Binds a local UNIX socket to a name.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @param name socket name.
 * @throws IOException
 */
static void BindLocalSocketToName(
        JNIEnv *env,
        jobject obj,
        int sd,
        const char *name) {
    struct sockaddr_un address;

    // Name length
    const size_t nameLength = strlen(name);

    // Path length is initiall equal to name length
    size_t pathLength = nameLength;

    // If name is not starting with a slash it is
    // in the abstract namespace
    bool abstractNamespace = ('/' != name[0]);

    // Abstract namespace requires having the first
    // byte of the path to be the zero byte, update
    // the path length to include the zero byte
    if (abstractNamespace) {
        pathLength++;
    }

    // Check the path length
    if (pathLength > sizeof(address.sun_path)) {
        // Throw an exception with error number
        ThrowException(env, "java/io/IOException", "Name is too big.");
    } else {
        // Clear the address bytes
        memset(&address, 0, sizeof(address));
        address.sun_family = PF_LOCAL;

        // Socket path
        char *sunPath = address.sun_path;

        // First byte must be zero to use the abstract namespace
        if (abstractNamespace) {
            *sunPath++ = NULL;
        }

        // Append the local name
        strcpy(sunPath, name);

        // Address length
        socklen_t addressLength =
                (offsetof(struct sockaddr_un, sun_path))
                + pathLength;

        // Unlink if the socket name is already binded
        unlink(address.sun_path);

        // Bind socket
        LogMessage(env, obj, "Binding to local name %s%s.",
                   (abstractNamespace) ? "(null)" : "",
                   name);

        if (-1 == bind(sd, (struct sockaddr *) &address, addressLength)) {
            // Throw an exception with error number
            ThrowErrnoException(env, "java/io/IOException", errno);
        }
    }
}

/**
 * Blocks and waits for incoming client connections on the
 * given socket.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @return client socket.
 * @throws IOException
 */
static int AcceptOnLocalSocket(
        JNIEnv *env,
        jobject obj,
        int sd) {
    // Blocks and waits for an incoming client connection
    // and accepts it
    LogMessage(env, obj, "Waiting for a client connection...");
    int clientSocket = accept(sd, NULL, NULL);

    // If client socket is not valid
    if (-1 == clientSocket) {
        // Throw an exception with error number
        ThrowErrnoException(env, "java/io/IOException", errno);
    }

    return clientSocket;
}

void Java_com_apress_echo_LocalEchoActivity_nativeStartLocalServer(
        JNIEnv *env,
        jobject obj,
        jstring name) {
    // Construct a new local UNIX socket.
    int serverSocket = NewLocalSocket(env, obj);
    if (NULL == env->ExceptionOccurred()) {
        // Get name as C string
        const char *nameText = env->GetStringUTFChars(name, NULL);
        if (NULL == nameText)
            goto exit;

        // Bind socket to a port number
        BindLocalSocketToName(env, obj, serverSocket, nameText);

        // Release the name text
        env->ReleaseStringUTFChars(name, nameText);

        // If bind is failed
        if (NULL != env->ExceptionOccurred())
            goto exit;

        // Listen on socket with a backlog of 4 pending connections
        ListenOnSocket(env, obj, serverSocket, 4);
        if (NULL != env->ExceptionOccurred())
            goto exit;

        // Accept a client connection on socket
        int clientSocket = AcceptOnLocalSocket(env, obj, serverSocket);
        if (NULL != env->ExceptionOccurred())
            goto exit;

        char buffer[MAX_BUFFER_SIZE];
        ssize_t recvSize;
        ssize_t sentSize;

        // Receive and send back the data
        while (1) {
            // Receive from the socket
            recvSize = ReceiveFromSocket(env, obj, clientSocket,
                                         buffer, MAX_BUFFER_SIZE);

            if ((0 == recvSize) || (NULL != env->ExceptionOccurred()))
                break;

            // Send to the socket
            sentSize = SendToSocket(env, obj, clientSocket,
                                    buffer, (size_t) recvSize);

            if ((0 == sentSize) || (NULL != env->ExceptionOccurred()))
                break;
        }

        // Close the client socket
        close(clientSocket);
    }

    exit:
    if (serverSocket > 0) {
        close(serverSocket);
    }
}

完整代码传送门:https://github.com/qq542391099/NativeSocket


猜你喜欢

转载自blog.csdn.net/u012874222/article/details/77843004
今日推荐