zoukankan      html  css  js  c++  java
  • socket 网络编程

    1. 基础socket库

    socket.h:

    /**
     * 网络套接字库
     */
    
    #ifndef Socket_h
    #define Socket_h
    
    #include <stdio.h>
    #include <string>
    
    #ifdef WIN32
    // windows
    #include <winsock.h>
    
    typedef int socklen_t;
    #else
    // linux, MacOS
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <arpa/inet.h>
    #include <errno.h>
    
    #define INVALID_SOCKET -1
    #define SOCKET_ERROR -1
    
    typedef int SOCKET;
    #endif
    
    #define SOCKET_BACKLOG 100
    
    namespace avalon {
        int socket_error();
        int socket_init();
        int socket_clean();
        void socket_debug(const char* message, ...);    
    
        class Socket {
        public:
            static Socket* create(SOCKET socket_fd);
            static Socket* create(int family, int type, int protocal = IPPROTO_IP);
            
        public:
            Socket(SOCKET socket_fd);
            Socket(int family, int type, int protocal = IPPROTO_IP);
            Socket& operator = (SOCKET socket_fd);
            virtual ~Socket();
            
            bool connect(const char* host, unsigned short port);
            bool bind(unsigned short port);
            bool listen(int backlog = SOCKET_BACKLOG);
            Socket* accept(char* client_host = nullptr);
            ssize_t send(const char* buffer, size_t len, int flag = 0);
            ssize_t recv(char* buffer, size_t len, int flag = 0);
            
            int close();
            
            SOCKET getSocketFD();
            
            void set_blocking(const bool blocking);
            
        private:
            SOCKET _socket_fd;
            
            int _family;
            int _type;
            int _protocal;
        };
    }
    
    #endif

    socket.cpp

    /**
     * 网络套接字库
     */
    
    #include "AvalonSocket.h"
    
    #ifdef WIN32
    #pragma comment(lib, "wsock32")
    #endif
    #define SOCKET_DEBUG_LEVEL 0
    
    namespace avalon {
        int socket_error() {
            int error = 0;
    #ifdef WIN32
            error = WSAGetLastError();
    #else
            error = errno;
    #endif
            
            printf("Avalon socket error: %d %s 
    ", error, strerror(error));
            
            return error;
        }
        
        void socket_debug(const char* message, ...) {
            char buf[1024] = "";
            
            va_list args;
            va_start(args, message);
            vsnprintf(buf, 1024, message, args);
            va_end(args);
            
            std::string error = "Avalon sokcet: ";
            error.append(buf);
            error.append("
    ");
            
            printf(error.c_str());
            
            if (SOCKET_DEBUG_LEVEL) {
                int error_no = socket_error();
                if (error_no != -1) {
                    throw error_no;
                }
            }
        }
        
        int socket_init() {
    #ifdef WIN32
            WSADATA wsadata;
            WORD version = MAKEWORD(2, 0);
            
            int ret = WSAStartup(version,&wsadata);
            if (ret) {
                socket_debug("Initilize winsock error");
                return -1;
            }
    #endif
            return 0;
        }
        
        int socket_clean() {
    #ifdef WIN32
            return WSACleanup();
    #endif
            return 0;
        }
        
        Socket* Socket::create(SOCKET socket_fd) {
            if (socket_fd < 0) {
                socket_debug("socket_fd(%d) is invailed.", socket_fd);
                return nullptr;
            }
            else {
                Socket* socket = new Socket(socket_fd);
                if (socket) {
                    return socket;
                }
                else {
                    socket_debug("Create avalon socket failed.");
                    return nullptr;
                }
            }
        }
        
        Socket* Socket::create(int family, int type, int protocal) {
            Socket* socket = new Socket(family, type, protocal);
            if (socket) {
                if (socket->getSocketFD() == INVALID_SOCKET) {
                    delete socket;
                    socket_debug("Create socket failed.");
                    return nullptr;
                }
                socket_debug("Create socket(%d) successfully.", socket->getSocketFD());
                return socket;
            }
            else {
                socket_debug("Create avalon socket failed.");
                return nullptr;
            }
        }
        
        Socket::Socket(SOCKET socket_fd)
        : _family(AF_INET)
        , _type(SOCK_STREAM)
        , _protocal(IPPROTO_IP) {
            _socket_fd = socket_fd;
        }
        
        Socket::Socket(int family, int type, int protocal)
        : _family(AF_INET)
        , _type(SOCK_STREAM)
        , _protocal(IPPROTO_IP) {
            _socket_fd = socket(family, type, protocal);
            if (_socket_fd != INVALID_SOCKET) {
                _family = family;
                _type = type;
                _protocal = protocal;
            }
        }
        
        Socket& Socket::operator = (SOCKET socket_fd) {
            _socket_fd = socket_fd;
            
            return *this;
        }
        
        Socket::~Socket() {
            if (_socket_fd != -1) {
                this->close();
            }
        }
        
        bool Socket::connect(const char* host, unsigned short port) {
            struct sockaddr_in remote_addr;
            remote_addr.sin_family = _family;
            remote_addr.sin_port = htons(port);
            inet_pton(_family, host, &remote_addr.sin_addr);
            if (errno == EAFNOSUPPORT) return false;
            
            int ret = ::connect(_socket_fd, (struct sockaddr*)(&remote_addr), sizeof(remote_addr));
            if (ret == SOCKET_ERROR) {
                socket_debug("Connect %s:%d failed.", host, port);
                socket_error();
                return false;
            }
            socket_debug("Connect %s:%d successfully.", host, port);
            return true;
        }
        
        bool Socket::bind(unsigned short port) {
            int opt = 1;
            if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0)
                return false;
            
            struct sockaddr_in remote_addr;
            remote_addr.sin_family = _family;
            remote_addr.sin_addr.s_addr = INADDR_ANY;
            remote_addr.sin_port = htons(port);
            
            int ret = ::bind(_socket_fd, (struct sockaddr*)(&remote_addr), sizeof(remote_addr));
            if (ret == SOCKET_ERROR) {
                socket_debug("Socket(%d) bind port(%d) failed.", _socket_fd, port);
                return false;
            }
            socket_debug("Socket(%d) bind port(%d) successfully.", _socket_fd, port);
            return true;
        }
        
        bool Socket::listen(int backlog) {
            int ret = ::listen(_socket_fd, backlog);
            if (ret == SOCKET_ERROR) {
                socket_debug("Socket(%d) listen failed.", _socket_fd);
                return false;
            }
            socket_debug("Socket(%d) Listen successfully.", _socket_fd);
            return true;
        }
        
        Socket* Socket::accept(char* client_host) {
            struct sockaddr_in com_socket;
            socklen_t len = sizeof(com_socket);
            
            SOCKET ret = -1;
            do {
                ret = ::accept(_socket_fd, (struct sockaddr*)(&com_socket), &len);
                if (ret == SOCKET_ERROR) {
                    if (errno == EINTR) continue;
                    else {
                        socket_debug("Socket(%d) accept failed.", _socket_fd);
                        socket_error();
                        return nullptr;
                    }
                }
                else break;
            } while (true);
            
            avalon::Socket* socket = avalon::Socket::create(ret);
            if (client_host) {
                sprintf(client_host, "%s", inet_ntoa(com_socket.sin_addr));
            }
            
            socket_debug("Socket(%d) accept successfully, client socket: %d ip: %s", _socket_fd, socket->getSocketFD(), inet_ntoa(com_socket.sin_addr));
            return socket;
        }
        
        ssize_t Socket::send(const char* buffer, size_t len, int flag) {
            ssize_t count = 0;
            
            while (count < len) {
                ssize_t bytes = ::send(_socket_fd, buffer + count, len - count, flag);
                count += bytes;
                
                if (bytes == -1 || bytes == 0) {
                    socket_error();
                    break;
                }
            }
            
            return count;
        }
        
        ssize_t Socket::recv(char* buffer, size_t len, int flag) {
            return ::recv(_socket_fd, buffer, len, flag);
        }
        
        ssize_t Socket::write(const char* buffer, size_t len) {
            ssize_t count = 0;
            
            while (count < len) {
                ssize_t bytes = ::write(_socket_fd, buffer + count, len - count);
                count += bytes;
                
                if (bytes == -1 || bytes == 0) {
                    socket_error();
                    break;
                }
            }
            
            return count;
        }
        
        ssize_t Socket::read(char* buffer, size_t len) {
            return ::read(_socket_fd, buffer, len);
        }
        
        void Socket::set_blocking(const bool blocking) {
            int opts;
            
            opts = fcntl(_socket_fd, F_GETFL);
            if (opts < 0) return;
            
            if (!blocking) opts = (opts | O_NONBLOCK);
            else opts = (opts & ~O_NONBLOCK);
            fcntl(_socket_fd, F_SETFL, opts);
        }
        
        int Socket::close() {
            int ret = -1;
    #ifdef WIN32
            ret = closesocket(_socket_fd);
    #else
            ret = ::close(_socket_fd);
    #endif
            if (ret == SOCKET_ERROR) {
                socket_debug("Socket(%d) close failed.", _socket_fd);
            }
            _socket_fd = -1;
            
            return ret;
        }
        
        SOCKET Socket::getSocketFD() {
            return _socket_fd;
        }
    }

    2. 多线程的模型:

    在accept成功之后,为每个通信socket创建新的进程和线程,单独用于处理服务器和客户端的通信。但是系统都会有创建进程数量的限制,在linux下,创建的线程也叫轻量级进程,所以即时创建的是线程也会受到系统的限制,通常这个默认限制是2048个,而且进程或者线程数量过多,也会导致进程或者线程切换的开销:

    客户端:

        avalon::Socket* socket = avalon::Socket::create(AF_INET, SOCK_STREAM);
        if (socket) {
            if (!socket->connect("127.0.0.1", 6666)) continue;
                
                char buf[1024] = "";
                sprintf(buf, "%d I am a client socket!", i);
                ssize_t bytes = socket->send(buf, strlen(buf), 0);
                
                char recvBuf[1024];
                while (true) {
                    memset(recvBuf, 0, 1024);
                    bytes = socket->recv(recvBuf, 1024);
                    if (bytes > 0) {
                        printf("%d recv data from remote: %d %s 
    ", i, bytes, recvBuf);
                    }
                    else if (bytes == 0) {
                        printf("remote socket %d cloese. 
    ", socket->getSocketFD());
                        
                        break;
                    }
                    else {
                        int error = avalon::socket_error();
                        printf("%d socket error: %d %s 
    ", i, error, strerror(error));
                        
                        break;
                    }
                }
            }    

    服务端:

    void communiction_handler(avalon::Socket* socket) {
        char buffer[1024];
        
        while (true) {
            if (!socket) continue;
            
            printf("thread %ld 
    ", std::this_thread::get_id());
            
            ssize_t bytes = socket->recv(buffer, 1024, 0);
            if (bytes > 0) {
                buffer[bytes] = '';
            
                printf("recv msg from client: %s 
    ", buffer);
                
                const char* data = "I am remote.0123456789abcdefg!wwwwwer";
                ssize_t sendedBytes = socket->send(data, strlen(data), 0);
            }
            else if (bytes == 0) {
                printf("client socket(%d) closed. thread(%ld) 
    ", socket->getSocketFD(), std::this_thread::get_id());
                
                socket->close();
                
                break;
            }
            else {
                int error_no = avalon::socket_error();
                printf("recv msg from client failed %d %s 
    ", error_no, strerror(error_no));
                
                socket->close();
                
                break;
            }
        }
    }
    
    int main(int argc, const char * argv[]) {
        // 多线程
        std::vector<std::thread> threads;
      
         avalon::Socket* listen_socket = avalon::Socket::create(AF_INET, SOCK_STREAM);
        
        do {
            if (!listen_socket->bind(6666)) break;
            if (!listen_socket->listen(10)) break;
            
            while (true) {
                // 多线程
                avalon::Socket* clientSocket = listen_socket->accept();
                if (clientSocket) {
                    threads.push_back(
                        std::move(
                            std::thread(communiction_handler, clientSocket)
                        )
                    );
                }
            } while (false);
    
    for(std::thread& thread : threads){
            thread.join();
        }
        
        delete listen_socket;
    }

    3. I/O多路复用

      内核一旦检测到某个I/O的读取条件就绪,就通知用户进程进行响应;

      多路复用一般用于需要同时处理多个文件描述符,多个套接字口,多种协议的情况;

      相比使用多进程和多线程的机制,I/O多路复用具有系统开销小的优势;

    (1)select模型:

    最大的问题就是连接数限制,通常是1024或者2048个,不过可以修改内核配置达到更多的连接数。但是由于select模型需要线性遍历fd集合,因此如果连接数改的过大,例如10万个,会导致线性遍历的性能问题,最后的结果可能是导致超时。其次,就是内存拷贝问题,select模型在fd消息通知用户的时候,是采用的将内核中的数据拷贝到用户空间中:

    服务端:

    //
    //  main.cpp
    //  SocketServer
    //
    //  Created by avl-showell on 16/8/8.
    //  Copyright © 2016年 avl-showell. All rights reserved.
    //
    
    #include <iostream>
    #include "socket/AvalonSocket.h"
    #include <mutex>
    #include <condition_variable>
    #include <chrono>
    #include <thread>
    #include <vector>
    // select
    #include <sys/select.h>
    #include <sys/time.h>
    #define MAX_CLIENT_SOCKET_COUNT 10000
    #define RECV_BUFFER_LEN 10
    
    int main(int argc, const char * argv[]) {
        std::vector<avalon::Socket*> socket_fds(MAX_CLIENT_SOCKET_COUNT, nullptr);
        fd_set read_fds, write_fds;
        struct timeval timeout;
        
        char recvBuf[RECV_BUFFER_LEN];
        
        avalon::Socket* listen_socket = avalon::Socket::create(AF_INET, SOCK_STREAM);
        
        do {
            if (!listen_socket->bind(6666)) break;
            if (!listen_socket->listen(10)) break;
            
            while (true) {
                // select
                int listen_socket_fd = listen_socket->getSocketFD();
                int max_socket_fd = listen_socket_fd;
                
                FD_ZERO(&read_fds);
                FD_SET(listen_socket_fd, &read_fds);
                
                for (int i = 0; i < MAX_CLIENT_SOCKET_COUNT; ++i) {
                    avalon::Socket* socket = socket_fds[i];
                    if (!socket) continue;
                    
                    SOCKET socket_fd = socket->getSocketFD();
                    if (socket_fd > 0) {
                        FD_SET(socket_fd, &read_fds);
                        if (socket_fd > max_socket_fd)
                            max_socket_fd = socket_fd;
                    }
                }
                
                timeout.tv_sec = 5;
                timeout.tv_usec = 0;
                
                int ret = select(max_socket_fd + 1, &read_fds, NULL, NULL, &timeout);
                if (ret == SOCKET_ERROR) {
                    avalon::socket_error();
                    break;
                }
                else if (ret == 0) {
                    printf("select socket timeout. 
    ");
                    continue;
                }
                else {
                    printf("_______________ 
    ");
                    
                    for (int i = 0; i < MAX_CLIENT_SOCKET_COUNT; ++i) {
                        avalon::Socket* socket = socket_fds[i];
                        if (!socket) continue;
                        
                        SOCKET socket_fd = socket->getSocketFD();
                        if (socket_fd > 0 && FD_ISSET(socket_fd, &read_fds)) {
                            int recvedBytes = 0;
                            
                            while (true) {
                                memset(recvBuf, 0, RECV_BUFFER_LEN);
                                int bytes = socket->recv(recvBuf, RECV_BUFFER_LEN);
                                if (bytes > 0) {
                                    recvedBytes += bytes;
                                    socket->send(recvBuf, RECV_BUFFER_LEN);
                                    break;
                                }
                                else {
                                    avalon::socket_error();
                                    
                                    delete socket;
                                    socket_fds[i] = nullptr;
                                    
                                    break;
                                }
                            }
                            
                            recvBuf[recvedBytes] = '';
                            printf("select: recv data from client: %s 
    ", recvBuf);

                  // 处理数据... } }
    if (FD_ISSET(listen_socket_fd, &read_fds)) { printf("select: new client connection. "); bool found = false; for (int i = 0; i < MAX_CLIENT_SOCKET_COUNT; ++i) { avalon::Socket* socket = socket_fds[i]; if (!socket) { avalon::Socket* clientSocket = listen_socket->accept(); if (clientSocket) { // clientSocket->set_blocking(false); socket_fds[i] = clientSocket; found = true; break; } } } if (!found) { printf("select: out of max sockets limit. "); } } } } } while (false); delete listen_socket; return 0; }

    (2) poll模型:

    poll模型和select模型类似,但是poll没有最大文件数量的限制,不过依然存在将消息从内核空间拷贝到用户空间的问题:

    服务端:

    #include <poll.h>
    
    #define MAX_CLIENT_SOCKET_COUNT 10
    #define RECV_BUFFER_LEN 10
    
    int main(int argc, const char * argv[]) {
        char recvBuf[RECV_BUFFER_LEN];
        
        avalon::Socket* listen_socket = avalon::Socket::create(AF_INET, SOCK_STREAM);
        
        // poll
        struct pollfd client_fds[MAX_CLIENT_SOCKET_COUNT];
        client_fds[0].fd = listen_socket->getSocketFD();
        client_fds[0].events = POLLIN;
        for (int i = 1; i < MAX_CLIENT_SOCKET_COUNT; ++i) {
            client_fds[i].fd = -1;
        }
        int max_socket = 0;
        
        do {
            if (!listen_socket->bind(6666)) break;
            if (!listen_socket->listen(10)) break;
            
            while (true) {
                int ready = poll(client_fds, max_socket + 1, 3000);
                if (ready == -1) {
                    avalon::socket_error();
                    break;
                }
                else if (ready == 0) {
                    printf("select socket timeout. 
    ");
                    continue;
                }
                
                printf("_______________ 
    ");
                
                if (client_fds[0].revents & POLLIN) {
                    printf("select: new client connection. 
    ");
                    
                    bool found = false;
                    
                    int i = 0;
                    for (i = 1; i < MAX_CLIENT_SOCKET_COUNT; ++i) {
                        avalon::Socket* socket = socket_fds[i];
                        
                        if (!socket) {
                            avalon::Socket* clientSocket = listen_socket->accept();
                            if (clientSocket) {
                                client_fds[i].fd = clientSocket->getSocketFD();
                                client_fds[i].events = POLLIN;
                                socket_fds[i] = clientSocket;
                                found = true;
                                break;
                            }
                        }
                    }
                    
                    if (!found) {
                        printf("select: out of max sockets limit. 
    ");
                    }
                    else {
                        if (i > max_socket)
                            max_socket = i;
                    }
                }
                
                for (int j = 1; j <= max_socket; ++j) {
                    avalon::Socket* socket = socket_fds[j];
                    if (!socket) continue;
                    
                    if (client_fds[j].revents & (POLLIN | POLLERR)) {
                        int recvedBytes = 0;
    
                        while (true) {
                            memset(recvBuf, 0, RECV_BUFFER_LEN);
                            int bytes = socket->read(recvBuf, RECV_BUFFER_LEN);
                            if (bytes > 0) {
                                recvedBytes += bytes;
                                int writedBytes = socket->write(recvBuf, RECV_BUFFER_LEN);
                                
                                recvBuf[bytes] = '';
                                printf("select: recv data from client: %s 
    ", recvBuf);
                                
                                if (bytes < RECV_BUFFER_LEN) break;
                            }
                            else {
                                avalon::socket_error();
                                
                                delete socket;
                                client_fds[j].fd = -1;
                                socket_fds[j] = nullptr;
                                
                                break;
                            }
                        }
                    }
                }
            }
        } while (false);
        
        for(std::thread& thread : threads){
            thread.join();
        }
        
        delete listen_socket;
        
        return 0;
    }

     (2) epoll模型

    epoll模型是poll模型的改进版本,没有文件描述符的限制,epoll只处理活跃的文件描述符,不会遍历整个集合,而且epoll使用了内核中的“共享内存”,减少了内存的拷贝:

    /* 实现功能:通过epoll, 处理多个socket
     * 监听一个端口,监听到有链接时,添加到epoll_event
     */
    #include "select.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <poll.h>
    #include <sys/epoll.h>
    #include <sys/time.h>
    #include <netinet/in.h>
    
    typedef struct _CLIENT{
        int fd;
        struct sockaddr_in addr; /* client's address information */
    } CLIENT;
    
    #define MYPORT 59000
    
    //最多处理的connect
    #define MAX_EVENTS 500
    
    //当前的连接数
    int currentClient = 0; 
    
    //数据接受 buf
    #define REVLEN 10
    char recvBuf[REVLEN];
    
    //EPOLL相关 
    //epoll描述符
    int epollfd;
    //事件数组
    struct epoll_event eventList[MAX_EVENTS];
    
    void AcceptConn(int srvfd);
    void RecvData(int fd);
    
    int main()
    {
        int i, ret, sinSize;
        int recvLen = 0;
        fd_set readfds, writefds;
        int sockListen, sockSvr, sockMax;
        int timeout;
        struct sockaddr_in server_addr;
        struct sockaddr_in client_addr;
        
        //socket
        if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            printf("socket error
    ");
            return -1;
        }
        
        bzero(&server_addr, sizeof(server_addr));
        server_addr.sin_family  =  AF_INET;
        server_addr.sin_port = htons(MYPORT);
        server_addr.sin_addr.s_addr  =  htonl(INADDR_ANY); 
        
        //bind
        if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
        {
            printf("bind error
    ");
            return -1;
        }
        
        //listen
        if(listen(sockListen, 5) < 0)
        {
            printf("listen error
    ");
            return -1;
        }
        
        //1. epoll 初始化
        epollfd = epoll_create(MAX_EVENTS);
        struct epoll_event event;
        event.events = EPOLLIN|EPOLLET;
        event.data.fd = sockListen;
        
        //2. epoll_ctrl
        if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sockListen, &event) < 0)
        {
            printf("epoll add fail : fd = %d
    ", sockListen);
            return -1;
        }
        
        //epoll
        while(1)
        {
            timeout=3000;                
            //3. epoll_wait
            int ret = epoll_wait(epollfd, eventList, MAX_EVENTS, timeout);
            
            if(ret < 0)
            {
                printf("epoll error
    ");
                break;
            }
            else if(ret == 0)
            {
                printf("timeout ...
    ");
                continue;
            }
            
            //直接获取了事件数量,给出了活动的流,这里是和poll区别的关键
            int n = 0;
            for(n=0; n<ret; n++)
            {
                //错误退出
                if ((eventList[n].events & EPOLLERR) ||
                    (eventList[n].events & EPOLLHUP) ||
                    !(eventList[n].events & EPOLLIN))
                {
                  printf ( "epoll error
    ");
                  close (eventList[n].data.fd);
                  return -1;
                }
                
                if (eventList[n].data.fd == sockListen)
                {
                    AcceptConn(sockListen);
            
                }else{
                    RecvData(eventList[n].data.fd);
                    //不删除
                 //   epoll_ctl(epollfd, EPOLL_CTL_DEL, pEvent->data.fd, pEvent);
                }
            }
        }
        
        close(epollfd);
        close(sockListen);
        
        printf("test
    ");
        return 0;
    }
    
    /**************************************************
    函数名:AcceptConn
    功能:接受客户端的链接
    参数:srvfd:监听SOCKET
    ***************************************************/
    void AcceptConn(int srvfd)
    {
        struct sockaddr_in sin;
        socklen_t len = sizeof(struct sockaddr_in);
        bzero(&sin, len);
    
        int confd = accept(srvfd, (struct sockaddr*)&sin, &len);
    
        if (confd < 0)
        {
           printf("bad accept
    ");
           return;
        }else
        {
            printf("Accept Connection: %d", confd);
        }
    
        //setnonblocking(confd);
    
        //4. epoll_wait
        //将新建立的连接添加到EPOLL的监听中
        struct epoll_event event;
        event.data.fd = confd;
        event.events =  EPOLLIN|EPOLLET;
        epoll_ctl(epollfd, EPOLL_CTL_ADD, confd, &event);
    }
    
    //读取数据
    void RecvData(int fd)
    {
        int ret;
        int recvLen = 0;
        
        memset(recvBuf, 0, REVLEN);
        printf("RecvData function
    ");
        
        if(recvLen != REVLEN)
        {
            while(1)
            {
                //recv数据
                ret = recv(fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
                if(ret == 0)
                {
                    recvLen = 0;
                    break;
                }
                else if(ret < 0)
                {
                    recvLen = 0;
                    break;
                }
                //数据接受正常
                recvLen = recvLen+ret;
                if(recvLen<REVLEN)
                {
                    continue;
                }
                else
                {
                    //数据接受完毕
                    printf("buf = %s
    ",  recvBuf);
                    recvLen = 0;
                    break;
                }
            }
        }
    
        printf("content is %s", recvBuf);
    }
  • 相关阅读:
    机器学习:K-近邻分类
    集体智慧编程2:聚类算法(分级聚类和K-均值聚类)(以博客的聚类为例,附有获取数据的代码)
    机器学习简介
    集体智慧编程1:推荐算法(基于协作性过滤collaborative filtering)(实例加代码)
    图片轮播
    A页面调到B页面,B页面关闭时A页面刷新
    css 上下滚动效果
    js数组的sort排序详解
    查看机器上安装的jdk能支持多大内存
    from表单如果未指定action,submit提交时候会执行当前url
  • 原文地址:https://www.cnblogs.com/iRidescent-ZONE/p/5757951.html
Copyright © 2011-2022 走看看