WebRTC--添加IOCP网络模型支持

来源:互联网 发布:intouch组态软件下载 编辑:程序博客网 时间:2024/05/19 17:52

一、起因

webRTC在windows平台默认使用的是WSAAsyncSelect模型,该模型需要有一个windows窗口的支持,而且伸缩性、性能都比较低。

关于WSAAsyncSelect模型的介绍可以参考Windows套接字I/O模型(3) – WSAAsyncSelect模型

因为webRTC是点对点的数据传输,对每一个端的性能要求并不高,采用WSAAsyncSelect模型完全是足够的。但是我们如果需要把rtc_base单独抽出来使用,那么在windows平台上加上IOCP模型的支持就很有必要了。

关于IOCP完成端口模型的介绍可以参考Windows套接字I/O模型(5) – 完成端口模型

二、实现

iocp.h, iocp.cc定义和实现iocp相关的结构体,通用功能。

iocp.h

#ifndef RTC_BASE_IOCP_H_#define RTC_BASE_IOCP_H_#if defined(WEBRTC_WIN)#include <winsock2.h>#include <MSWSock.h>#include <vector>#define MAX_BUFFER_LEN        8192  #define EXIT_CODE             0namespace IOCP {    typedef enum _OPERATION_TYPE    {        ACCEPT_POSTED,        CONNECT_POSTED,        SEND_POSTED,        RECV_POSTED,        NULL_POSTED    }OPERATION_TYPE;    typedef struct _PER_IO_CONTEXT    {        OVERLAPPED     overlapped;                    SOCKET         socket;        WSABUF         wsa_buffer;        char           buffer[MAX_BUFFER_LEN];        OPERATION_TYPE operation_type;        _PER_IO_CONTEXT() {            ZeroMemory(&overlapped, sizeof(overlapped));            ZeroMemory(buffer, MAX_BUFFER_LEN);            socket = INVALID_SOCKET;            wsa_buffer.buf = buffer;            wsa_buffer.len = MAX_BUFFER_LEN;            operation_type = NULL_POSTED;        }        ~_PER_IO_CONTEXT() {            // don't close socket        }        void ResetBuffer() {            ZeroMemory(buffer, MAX_BUFFER_LEN);        }        const char* GetBuffer() const {            return wsa_buffer.buf;        }        ULONG GetBufferLength() const {            return wsa_buffer.len;        }    } PER_IO_CONTEXT;    typedef struct _PER_SOCKET_CONTEXT {        SOCKET      socket;         SOCKADDR_IN client_addr;        std::vector<_PER_IO_CONTEXT*> io_ctx_array;        _PER_SOCKET_CONTEXT() {            socket = INVALID_SOCKET;            memset(&client_addr, 0, sizeof(client_addr));        }        ~_PER_SOCKET_CONTEXT()        {            if (socket != INVALID_SOCKET) {                closesocket(socket);                socket = INVALID_SOCKET;            }            for (size_t i = 0; i < io_ctx_array.size(); i++) {                delete io_ctx_array[i];            }            io_ctx_array.clear();        }        _PER_IO_CONTEXT* GetNewIoContext() {            _PER_IO_CONTEXT* p = new _PER_IO_CONTEXT;            io_ctx_array.push_back(p);            return p;        }        void RemoveContext(_PER_IO_CONTEXT* pContext) {            for (std::vector<_PER_IO_CONTEXT*>::iterator it = io_ctx_array.begin();                 it != io_ctx_array.end(); it++) {                if (pContext == *it) {                    delete pContext;                    pContext = NULL;                    io_ctx_array.erase(it);                    break;                }            }        }    } PER_SOCKET_CONTEXT;    int GetNumberOfProcesser();    HANDLE CreateNewCompletionPort();    BOOL AssociateDeviceWithCompletionPort(HANDLE completion_port, HANDLE device, DWORD completion_key);    LPFN_ACCEPTEX GetAcceptExFnPointer(SOCKET s);    LPFN_CONNECTEX GetConnectExFnPointer(SOCKET s);    LPFN_GETACCEPTEXSOCKADDRS GetAcceptExSockAddrsFnPointer(SOCKET s);};#endif#endif // IOCP_H_

iocp.cc

#include "iocp.h"#if defined(WEBRTC_WIN)namespace IOCP {    int GetNumberOfProcesser() {        SYSTEM_INFO si;        GetSystemInfo(&si);        return si.dwNumberOfProcessors;    }    HANDLE CreateNewCompletionPort() {        return CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);    }    BOOL AssociateDeviceWithCompletionPort(HANDLE completion_port, HANDLE device, DWORD completion_key) {        HANDLE h = CreateIoCompletionPort(device, completion_port, completion_key, 0);        return (h == completion_port);    }    LPFN_ACCEPTEX GetAcceptExFnPointer(SOCKET s) {        LPFN_ACCEPTEX fn = NULL;         GUID GuidAcceptEx = WSAID_ACCEPTEX;        DWORD bytes = 0;        if (SOCKET_ERROR == WSAIoctl(            s,            SIO_GET_EXTENSION_FUNCTION_POINTER,            &GuidAcceptEx,            sizeof(GuidAcceptEx),            &fn,            sizeof(fn),            &bytes,            NULL,            NULL)) {            return NULL;        }        return fn;    }    LPFN_CONNECTEX GetConnectExFnPointer(SOCKET s) {        LPFN_CONNECTEX fn = NULL;        GUID GuidConnectEx = WSAID_CONNECTEX;        DWORD bytes = 0;        if (SOCKET_ERROR == WSAIoctl(            s,            SIO_GET_EXTENSION_FUNCTION_POINTER,            &GuidConnectEx,            sizeof(GuidConnectEx),            &fn,            sizeof(fn),            &bytes,            NULL,            NULL)) {            return NULL;        }        return fn;    }    LPFN_GETACCEPTEXSOCKADDRS GetAcceptExSockAddrsFnPointer(SOCKET s) {        LPFN_GETACCEPTEXSOCKADDRS fn = NULL;        GUID GuidGetAcceptExSockAddrs = WSAID_GETACCEPTEXSOCKADDRS;        DWORD bytes = 0;        if (SOCKET_ERROR == WSAIoctl(            s,            SIO_GET_EXTENSION_FUNCTION_POINTER,            &GuidGetAcceptExSockAddrs,            sizeof(GuidGetAcceptExSockAddrs),            &fn,            sizeof(fn),            &bytes,            NULL,            NULL)) {            return NULL;        }        return fn;    }}#endif

overlappedsocket.h, overlappedsocket.cc定义了rtc::OverlappedSocket类。
在webRTC中Socket都派生自rtc::Socket–>rtc::AsyncSocket,虽说IOCP模型也是异步socket,但rtc::AsyncSocket接口和信号的定义是根据WSAAsyncSelect模型来的,不适应于IOCP模型,例如:
AsyncSocket中的SignalReadEvent信号

sigslot::signal1<AsyncSocket*,sigslot::multi_threaded_local> 

它只有一个参数AsyncSocket,在收到该信号时,再通过AsyncSocket::Read方法去获取数据。而IOCP是在收到通知时,数据已经获取完成了,所以webRTC提供的基类的接口、信号不是适用于IOCP模型,故OverlappedSocket没派生自任何基类。

overlappedsocket.h

#ifndef RTC_BASE_OVERLAPPED_SOCKET_H_#define RTC_BASE_OVERLAPPED_SOCKET_H_#include "rtc_base/iocp.h"#include "rtc_base/socket.h"#include "rtc_base/asyncsocket.h"#include "rtc_base/event.h"#include "rtc_base/thread.h"#if defined(WEBRTC_WIN)namespace rtc {    class OverlappedSocket {    public:        OverlappedSocket();        virtual ~OverlappedSocket();        bool CreateT(int family, int type);        SocketAddress GetLocalAddress() const;        SocketAddress GetRemoteAddress() const;        int Bind(const SocketAddress& addr);        int Connect(const SocketAddress& addr);        int Send(const void* buffer, size_t length, IOCP::PER_IO_CONTEXT* io_ctx = NULL);        int Listen(int backlog);        bool Accept();        int Close();        int GetError() const;        void SetError(int error);        Socket::ConnState GetState() const;        int GetOption(Socket::Option opt, int* value);        int SetOption(Socket::Option opt, int value);        void Clone(OverlappedSocket *socket);    public:        class CompletionIOHandler : public Thread {        public:            CompletionIOHandler(OverlappedSocket* parent, int index);            ~CompletionIOHandler();            void Run() override;        private:            OverlappedSocket*parent_;        };    public:        sigslot::signal1<OverlappedSocket*, sigslot::multi_threaded_local> SignalAcceptEvent;        sigslot::signal2<OverlappedSocket*, const IOCP::PER_IO_CONTEXT*, sigslot::multi_threaded_local> SignalReadEvent;        sigslot::signal2<OverlappedSocket*, const IOCP::PER_IO_CONTEXT*, sigslot::multi_threaded_local> SignalWriteEvent;        sigslot::signal1<OverlappedSocket*> SignalConnectEvent;     // connected        sigslot::signal2<OverlappedSocket*, int> SignalCloseEvent;       // closed    private:        bool InitIOCP(SOCKET s);        void UpdateLastError();        bool PostAccept(IOCP::PER_IO_CONTEXT* io_ctx);        bool PostRecv(IOCP::PER_IO_CONTEXT* io_ctx);        bool PostSend(IOCP::PER_IO_CONTEXT* io_ctx, const void* msg, size_t msg_len);        bool PostConnect(IOCP::PER_IO_CONTEXT* io_ctx, const SocketAddress& addr);    private:        int error_;        int family_;        int type_;        Event exit_;        HANDLE iocp_;        int workthread_num_;        std::vector<std::unique_ptr<CompletionIOHandler>> workthreads_;        IOCP::PER_SOCKET_CONTEXT* own_socket_ctx_;        LPFN_CONNECTEX connectex_fn_;        LPFN_ACCEPTEX acceptex_fn_;        LPFN_GETACCEPTEXSOCKADDRS getacceptexsockaddrs_fn_;        Socket::ConnState state_;        SocketAddress addr_;         // address that we connected to (see DoConnect)        SocketAddress remote_addr_;        int64_t connect_time_;        bool closing_;        int close_error_;    };}#endif#endif

overlappedsocket.cc

#include "rtc_base/overlappedsocket.h"#include "rtc_base/win32socketserver.h"#include "rtc_base/checks.h"#include "rtc_base/logging.h"#include <process.h>#include "rtc_base/timeutils.h"#include "rtc_base/nullsocketserver.h"#if defined(WEBRTC_WIN)namespace rtc {    OverlappedSocket::CompletionIOHandler::CompletionIOHandler(OverlappedSocket* parent, int index) :         Thread(std::unique_ptr<SocketServer>(new NullSocketServer())),        parent_(parent)    {        std::string thread_name = "OverlappedSocketWorkThread_";        SetName(thread_name + std::to_string(index), this);        Start();    }    OverlappedSocket::CompletionIOHandler::~CompletionIOHandler()    {    }    void OverlappedSocket::CompletionIOHandler::Run()    {        RTC_DCHECK(parent_);        DWORD transferred_bytes = 0;        OverlappedSocket *overlapped_socket = NULL;        OVERLAPPED *overlapped = NULL;        DWORD gle = 0;        while (!parent_->exit_.Wait(0)) {            BOOL ret = GetQueuedCompletionStatus(parent_->iocp_, &transferred_bytes, (PULONG_PTR)&overlapped_socket, &overlapped, INFINITE);            if (overlapped_socket == EXIT_CODE) {                break;            }            if (ret == FALSE) {                gle = GetLastError();                if (gle == WAIT_TIMEOUT) {                    RTC_NOTREACHED();                    continue;                }                else if (gle == ERROR_NETNAME_DELETED) {                    parent_->SignalCloseEvent(overlapped_socket, gle);                    continue;                }                else {                    parent_->SignalCloseEvent(overlapped_socket, gle);                    break;                }            }            else {                IOCP::PER_IO_CONTEXT *io_ctx = CONTAINING_RECORD(overlapped, IOCP::PER_IO_CONTEXT, overlapped);                if ((transferred_bytes == 0) && (io_ctx->operation_type == IOCP::RECV_POSTED || io_ctx->operation_type == IOCP::SEND_POSTED)) {                    parent_->SignalCloseEvent(overlapped_socket, gle);                    continue;                }                if (io_ctx->operation_type == IOCP::ACCEPT_POSTED) {                    sockaddr_storage* ClientAddr = NULL;                    sockaddr_storage* LocalAddr = NULL;                    int remoteLen = sizeof(sockaddr_storage);                    int localLen = sizeof(sockaddr_storage);                    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms738516(v=vs.85).aspx                    parent_->getacceptexsockaddrs_fn_(io_ctx->wsa_buffer.buf,                        0,                        sizeof(sockaddr_storage) + 16,                        sizeof(sockaddr_storage) + 16,                        (LPSOCKADDR*)&LocalAddr,                        &localLen,                        (LPSOCKADDR*)&ClientAddr,                        &remoteLen);                    SocketAddress remote_addr;                    SocketAddressFromSockAddrStorage(*ClientAddr, &remote_addr);                    OverlappedSocket* new_overlapped_socket = new OverlappedSocket();                    new_overlapped_socket->remote_addr_ = remote_addr;                    IOCP::PER_SOCKET_CONTEXT* new_socket_ctx = new IOCP::PER_SOCKET_CONTEXT();                    new_socket_ctx->socket = io_ctx->socket;                    new_overlapped_socket->own_socket_ctx_ = new_socket_ctx;                    overlapped_socket->Clone(new_overlapped_socket);                    if (!IOCP::AssociateDeviceWithCompletionPort(parent_->iocp_, (HANDLE)new_overlapped_socket->own_socket_ctx_->socket, (DWORD)new_overlapped_socket)) {                        delete new_socket_ctx;                        new_socket_ctx = NULL;                    }                    else {                        new_overlapped_socket->connect_time_ = TimeMillis();                        // post new accept                        if (!parent_->PostAccept(io_ctx)) {                            RTC_NOTREACHED();                        }                        parent_->SignalAcceptEvent(new_overlapped_socket);                        // post recv                        IOCP::PER_IO_CONTEXT *new_io_ctx = new_socket_ctx->GetNewIoContext();                        new_io_ctx->socket = new_socket_ctx->socket;                        if (!parent_->PostRecv(new_io_ctx)) {                            new_socket_ctx->RemoveContext(new_io_ctx);                        }                    }                }                else if (io_ctx->operation_type == IOCP::RECV_POSTED) {                    parent_->SignalReadEvent(overlapped_socket, io_ctx);                    if (!parent_->PostRecv(io_ctx)) {                        overlapped_socket->own_socket_ctx_->RemoveContext(io_ctx);                    }                }                else if (io_ctx->operation_type == IOCP::SEND_POSTED) {                    parent_->SignalWriteEvent(overlapped_socket, io_ctx);                    overlapped_socket->own_socket_ctx_->RemoveContext(io_ctx);                }                else if (io_ctx->operation_type == IOCP::CONNECT_POSTED) {                    parent_->SignalConnectEvent(overlapped_socket);                }                else {                    RTC_NOTREACHED();                }            }        }    }    OverlappedSocket::OverlappedSocket() :        error_(0),        close_error_(0),        workthread_num_(0),        own_socket_ctx_(NULL),        iocp_(INVALID_HANDLE_VALUE),        exit_(true, false),        state_(Socket::CS_CLOSED),        connect_time_(0),        closing_(false),        connectex_fn_(NULL),        acceptex_fn_(NULL),        getacceptexsockaddrs_fn_(NULL),        family_(AF_UNSPEC),        type_(0) {    }    OverlappedSocket::~OverlappedSocket() {        Close();    }    bool OverlappedSocket::CreateT(int family, int type) {        Close();        int proto = (SOCK_DGRAM == type) ? IPPROTO_UDP : IPPROTO_TCP;        SOCKET s = ::WSASocket(family, type, proto, nullptr, 0, WSA_FLAG_OVERLAPPED);        if (s == INVALID_SOCKET) {            UpdateLastError();            return false;        }        if (!InitIOCP(s)) {            return false;        }        family_ = family;        type_ = type;        return true;    }    SocketAddress OverlappedSocket::GetLocalAddress() const {        sockaddr_storage addr = { 0 };        socklen_t addrlen = sizeof(addr);        int result = ::getsockname(own_socket_ctx_->socket, reinterpret_cast<sockaddr*>(&addr),            &addrlen);        SocketAddress address;        if (result >= 0) {            SocketAddressFromSockAddrStorage(addr, &address);        }        else {            RTC_LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket="                << own_socket_ctx_->socket;        }        return address;    }    SocketAddress OverlappedSocket::GetRemoteAddress() const {        //sockaddr_storage addr = { 0 };        //socklen_t addrlen = sizeof(addr);        //int result = ::getpeername(socket_, reinterpret_cast<sockaddr*>(&addr),        //  &addrlen);        //SocketAddress address;        //if (result >= 0) {        //  SocketAddressFromSockAddrStorage(addr, &address);        //}        //else {        //  RTC_LOG(LS_WARNING)        //      << "GetRemoteAddress: unable to get remote addr, socket=" << socket_ << ",GLE=" << WSAGetLastError();        //}        //return address;        return remote_addr_;    }    int OverlappedSocket::Bind(const SocketAddress & addr) {        RTC_DCHECK(own_socket_ctx_->socket != INVALID_SOCKET);        if (own_socket_ctx_->socket == INVALID_SOCKET)            return SOCKET_ERROR;        sockaddr_storage saddr;        size_t len = addr.ToSockAddrStorage(&saddr);        int err = ::bind(own_socket_ctx_->socket,            reinterpret_cast<sockaddr*>(&saddr),            static_cast<int>(len));        UpdateLastError();        return err;    }    int OverlappedSocket::Connect(const SocketAddress & addr) {        RTC_DCHECK(own_socket_ctx_ != NULL);        if (own_socket_ctx_ == NULL) {            return SOCKET_ERROR;        }        IOCP::PER_IO_CONTEXT* io_ctx = own_socket_ctx_->GetNewIoContext();        io_ctx->socket = own_socket_ctx_->socket;        if (!PostConnect(io_ctx, addr)) {            own_socket_ctx_->RemoveContext(io_ctx);            return SOCKET_ERROR;        }        return 0;    }    int OverlappedSocket::Send(const void * buffer, size_t length, IOCP::PER_IO_CONTEXT* io_ctx /* = NULL*/) {        RTC_DCHECK(own_socket_ctx_ != NULL);        if (own_socket_ctx_ == NULL) {            return SOCKET_ERROR;        }        if (!io_ctx) {            io_ctx = own_socket_ctx_->GetNewIoContext();            io_ctx->socket = own_socket_ctx_->socket;        }        if (!PostSend(io_ctx, buffer, length)) {            own_socket_ctx_->RemoveContext(io_ctx);            return SOCKET_ERROR;        }        return 0;    }    int OverlappedSocket::Listen(int backlog) {        int err = ::listen(own_socket_ctx_->socket, backlog);        UpdateLastError();        if (err == 0)            state_ = Socket::CS_CONNECTING;        return err;    }    bool OverlappedSocket::Accept() {        int success = 0;        for (int i = 0; i < workthread_num_; i++) {            IOCP::PER_IO_CONTEXT *io_ctx = own_socket_ctx_->GetNewIoContext();            if (!PostAccept(io_ctx)) {                own_socket_ctx_->RemoveContext(io_ctx);            }            else {                success++;            }        }        return success > 0;    }    int OverlappedSocket::Close() {        int err = 0;        exit_.Set();        for (int i = 0; i < workthread_num_; i++) {            PostQueuedCompletionStatus(iocp_, 0, (DWORD)EXIT_CODE, NULL);        }        workthreads_.clear();        workthread_num_ = 0;        if (own_socket_ctx_) {            if (own_socket_ctx_->socket != INVALID_SOCKET) {                err = ::closesocket(own_socket_ctx_->socket);                own_socket_ctx_->socket = INVALID_SOCKET;                closing_ = false;                close_error_ = 0;                UpdateLastError();            }            delete own_socket_ctx_;            own_socket_ctx_ = NULL;        }        if (iocp_ != INVALID_HANDLE_VALUE) {            CloseHandle(iocp_);            iocp_ = INVALID_HANDLE_VALUE;        }        exit_.Reset();        connectex_fn_ = NULL;        acceptex_fn_ = NULL;        getacceptexsockaddrs_fn_ = NULL;        addr_.Clear();        state_ = Socket::CS_CLOSED;        return err;    }    int OverlappedSocket::GetError() const {        return error_;    }    void OverlappedSocket::SetError(int error) {        error_ = error;    }    Socket::ConnState OverlappedSocket::GetState() const {        return state_;    }    int OverlappedSocket::GetOption(Socket::Option opt, int * value) {        int slevel;        int sopt;        if (Win32Socket::TranslateOption(opt, &slevel, &sopt) == -1)            return -1;        char* p = reinterpret_cast<char*>(value);        int optlen = sizeof(value);        return ::getsockopt(own_socket_ctx_->socket, slevel, sopt, p, &optlen);    }    int OverlappedSocket::SetOption(Socket::Option opt, int value) {        int slevel;        int sopt;        if (Win32Socket::TranslateOption(opt, &slevel, &sopt) == -1)            return -1;        const char* p = reinterpret_cast<const char*>(&value);        return ::setsockopt(own_socket_ctx_->socket, slevel, sopt, p, sizeof(value));    }    void OverlappedSocket::Clone(OverlappedSocket *socket) {        socket->family_ = this->family_;        socket->type_ = this->type_;    }    bool OverlappedSocket::InitIOCP(SOCKET s) {        iocp_ = IOCP::CreateNewCompletionPort();        if (iocp_ == INVALID_HANDLE_VALUE) {            return false;        }        exit_.Reset();        workthread_num_ = IOCP::GetNumberOfProcesser() * 2;        for (int i = 0; i < workthread_num_; i++) {            std::unique_ptr<CompletionIOHandler> handler = std::make_unique<CompletionIOHandler>(this, i);            workthreads_.push_back(std::move(handler));        }        own_socket_ctx_ = new IOCP::PER_SOCKET_CONTEXT();        own_socket_ctx_->socket = s;        if (!IOCP::AssociateDeviceWithCompletionPort(iocp_, (HANDLE)own_socket_ctx_->socket, (DWORD)this)) {            Close();            return false;        }        connectex_fn_ = IOCP::GetConnectExFnPointer(own_socket_ctx_->socket);        RTC_DCHECK(connectex_fn_);        acceptex_fn_ = IOCP::GetAcceptExFnPointer(own_socket_ctx_->socket);        RTC_DCHECK(acceptex_fn_);        getacceptexsockaddrs_fn_ = IOCP::GetAcceptExSockAddrsFnPointer(own_socket_ctx_->socket);        RTC_DCHECK(getacceptexsockaddrs_fn_);        return true;    }    void OverlappedSocket::UpdateLastError() {        error_ = WSAGetLastError();    }    bool OverlappedSocket::PostAccept(IOCP::PER_IO_CONTEXT* io_ctx) {        if (io_ctx == NULL)            return false;        int proto = (SOCK_DGRAM == type_) ? IPPROTO_UDP : IPPROTO_TCP;        io_ctx->operation_type = IOCP::ACCEPT_POSTED;        io_ctx->ResetBuffer();        io_ctx->socket = WSASocket(family_, type_, proto, NULL, 0, WSA_FLAG_OVERLAPPED);        if (io_ctx->socket == INVALID_SOCKET) {            UpdateLastError();            return false;        }        DWORD bytes = 0;        if (acceptex_fn_(own_socket_ctx_->socket,            io_ctx->socket,            io_ctx->wsa_buffer.buf,            0,            sizeof(sockaddr_storage) + 16,            sizeof(sockaddr_storage) + 16,            &bytes,            &io_ctx->overlapped) == FALSE) {            int gle = WSAGetLastError();            if (gle != WSA_IO_PENDING) {                UpdateLastError();                return false;            }        }        UpdateLastError();        return true;    }    bool OverlappedSocket::PostRecv(IOCP::PER_IO_CONTEXT* io_ctx) {        if (io_ctx == NULL)            return false;        io_ctx->operation_type = IOCP::RECV_POSTED;        io_ctx->ResetBuffer();        DWORD recv_bytes = 0;        DWORD flags = 0;        int ret = WSARecv(io_ctx->socket, &io_ctx->wsa_buffer, 1, &recv_bytes, &flags, &io_ctx->overlapped, NULL);        if (ret == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING) {            UpdateLastError();            return false;        }        return true;    }    bool OverlappedSocket::PostSend(IOCP::PER_IO_CONTEXT* io_ctx, const void* msg, size_t msg_len) {        if (io_ctx == NULL)            return false;        io_ctx->operation_type = IOCP::SEND_POSTED;        memcpy(io_ctx->wsa_buffer.buf, msg, msg_len);        io_ctx->wsa_buffer.len = msg_len;        DWORD sent_bytes = 0;        int ret = WSASend(io_ctx->socket, &io_ctx->wsa_buffer, 1, &sent_bytes, 0, &io_ctx->overlapped, NULL);        if (ret == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING) {            UpdateLastError();            return false;        }        UpdateLastError();        return true;    }    bool OverlappedSocket::PostConnect(IOCP::PER_IO_CONTEXT* io_ctx, const SocketAddress& addr) {        if (io_ctx == NULL)            return false;        io_ctx->operation_type = IOCP::CONNECT_POSTED;        io_ctx->ResetBuffer();        // ConnectEx requires the socket to be initially bound.        struct sockaddr_in addr0 = { 0 };        addr0.sin_family = family_;        addr0.sin_addr.s_addr = INADDR_ANY;        addr0.sin_port = 0;        int ret = bind(io_ctx->socket, (SOCKADDR*)&addr0, sizeof(addr0));        if (ret != 0) {            UpdateLastError();            return false;        }        sockaddr_storage saddr;        size_t len = addr.ToSockAddrStorage(&saddr);        ret = connectex_fn_(io_ctx->socket,            reinterpret_cast<const sockaddr*>(&saddr),            len,            NULL,            0,            NULL,            &io_ctx->overlapped);        int gle = WSAGetLastError();        if (ret == SOCKET_ERROR && gle != WSA_IO_PENDING) {            UpdateLastError();            return false;        }        UpdateLastError();        return true;    }}#endif

win32iocpserver.h, win32iocpserver.cc定义了Win32IOCPServer类,提供使用OverlappedSocket实现IOCP服务端的功能。

win32iocpserver.h

#ifndef RTC_BASE_WIN32_IOCP_SERVER_H_#define RTC_BASE_WIN32_IOCP_SERVER_H_#if defined(WEBRTC_WIN)#include "rtc_base/socketfactory.h"#include "rtc_base/socketserver.h"#include "rtc_base/iocp.h"#include "rtc_base/criticalsection.h"namespace rtc {    class OverlappedSocket;    typedef std::list<OverlappedSocket*> ClientList;    class Win32IOCPServer : public sigslot::has_slots<> {    public:        Win32IOCPServer();        virtual ~Win32IOCPServer();        bool Start(const SocketAddress &addr, int family, int type);        bool Stop();        int64_t GetStartTime() const;        void OnAcceptEvent(OverlappedSocket* socket);        void OnReadEvent(OverlappedSocket* socket,            const IOCP::PER_IO_CONTEXT* io_ctx);        void OnWriteEvent(OverlappedSocket* socket,            const IOCP::PER_IO_CONTEXT* io_ctx);        void OnCloseEvent(OverlappedSocket* socket, int error);    private:        int64_t start_time_;        OverlappedSocket* socket_;        ClientList client_list_;        CriticalSection crit_;  // CriticalSection for client_list_    };}#endif#endif // RTC_BASE_WIN32_IOCP_SERVER_H_

win32iocpserver.cc

#include "rtc_base/win32iocpserver.h"#include "rtc_base/timeutils.h"#include "rtc_base/logging.h"#include "rtc_base/overlappedsocket.h"namespace rtc {    Win32IOCPServer::Win32IOCPServer()         : start_time_(0)     {    }    Win32IOCPServer::~Win32IOCPServer() {    }    bool Win32IOCPServer::Start(const SocketAddress & addr, int family, int type) {        socket_ = new OverlappedSocket();        RTC_DCHECK(socket_);        socket_->SignalAcceptEvent.connect(this, &Win32IOCPServer::OnAcceptEvent);        socket_->SignalReadEvent.connect(this, &Win32IOCPServer::OnReadEvent);        socket_->SignalWriteEvent.connect(this, &Win32IOCPServer::OnWriteEvent);        socket_->SignalCloseEvent.connect(this, &Win32IOCPServer::OnCloseEvent);        if (!socket_->CreateT(family, type)) {            RTC_LOG(LS_WARNING) << "CreateT: failed, error=" << socket_->GetError();            return false;        }        if (socket_->Bind(addr) == SOCKET_ERROR) {            RTC_LOG(LS_WARNING) << "Bind: failed, error=" << socket_->GetError();            return false;        }        if (socket_->Listen(SOMAXCONN) == SOCKET_ERROR) {            RTC_LOG(LS_WARNING) << "Listen: failed, error=" << socket_->GetError();            return false;        }        if (!socket_->Accept()) {            RTC_LOG(LS_WARNING) << "Accept: failed, error=" << socket_->GetError();            return false;        }        start_time_ = TimeMillis();        return true;    }    bool Win32IOCPServer::Stop() {        if (socket_->Close() == SOCKET_ERROR) {            RTC_LOG(LS_WARNING) << "Close: failed, error=" << socket_->GetError();            return false;        }        {            CritScope cs(&crit_);            for (ClientList::iterator it = client_list_.begin(); it != client_list_.end(); it++) {                RTC_DCHECK((*it) != NULL);                (*it)->Close();                delete (*it);            }            client_list_.clear();        }        start_time_ = 0;        delete socket_;        socket_ = NULL;        return true;    }    int64_t Win32IOCPServer::GetStartTime() const {        return start_time_;    }    void Win32IOCPServer::OnAcceptEvent(OverlappedSocket * socket) {        RTC_DCHECK(socket);        RTC_LOG(LS_INFO) << "[" << socket->GetRemoteAddress().ToString() << "] [Connected]";        {            CritScope cs(&crit_);            client_list_.push_back(socket);        }    }    void Win32IOCPServer::OnReadEvent(OverlappedSocket * socket, const IOCP::PER_IO_CONTEXT * io_ctx) {        RTC_DCHECK(socket);        RTC_DCHECK(io_ctx);        RTC_LOG(LS_INFO) << "[" << socket->GetRemoteAddress().ToString() << "] [RECV] " << io_ctx->GetBuffer();    }    void Win32IOCPServer::OnWriteEvent(OverlappedSocket * socket, const IOCP::PER_IO_CONTEXT * io_ctx) {        RTC_DCHECK(socket);        RTC_DCHECK(io_ctx);        RTC_LOG(LS_INFO) << "[" << socket->GetRemoteAddress().ToString() << "] [SEND] " << io_ctx->GetBuffer();    }    void Win32IOCPServer::OnCloseEvent(OverlappedSocket * socket, int error) {        RTC_DCHECK(socket);        RTC_LOG(LS_INFO) << "[" << socket->GetRemoteAddress().ToString() << "] [Disconnected] error=" << error;        socket->Close();        {            CritScope cs(&crit_);            client_list_.remove(socket);        }        delete socket;        socket = NULL;    }}

只需要将上面6个文件加入到rtc_base工程中即可。

如何使用visual studio管理和生成rtc_base,参考WebRTC–rtc_base库移植

三、测试

测试工程已经上传到码云:

git clone https://gitee.com/china_jeffery/webrtc.git

工程文件见webrtc\src\msvc\test目录。

后期更新也会同步到该git.

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 怎样可以留学 艺术类留学中介 美国本科留学条件 出国留学需要准备什么 美国研究生留学条件 比较好的留学中介 研究生出国留学费用 如何去德国留学 办出国留学机构 留学机构哪家比较好 出国留学花费 容易出国留学的专业 出国留学有什么要求 出国留学研究生的条件 怎么样可以留学 英国出国留学中介 留学出国中介哪家好 再来人留学中介 个人申请留学 留学出国的条件 广东省出国留学 留学有什么要求 找中介出国留学 中介澳洲留学机构 申请出国留学的条件 出国留学要多少费用 好的留学中介机构 出国大学留学费用 出国留学信息 留学美国本科中介 出国要多少钱 金吉利 出国读研费用 留学生学历认证 学历认证网 国外学历认证 怎么申请国外研究生 出国考研条件 去国外读研究生的条件 国外读研 国外读研申请条件