更改在c

时间:2018-03-21 03:29:16

标签: c sockets tcp

我正在尝试实现套接字库。一切都做得很好,直到我达到接受功能。我调查了堆栈溢出,我说它不会返回,直到客户端通过这个连接,但如果它不是在blockmode。所以,我想知道:如何改变听到NONBLOCK模式?

这是我的标题:

#ifndef NET_SOCKET_H
#define NET_SOCKET_H

#ifdef __cplusplus
extern "C" {
#endif

#if defined(WIN32) || defined(WINDOWS_XP)
#include <winsock2.h>
#endif

#include <type-of/include/type.h>
#include <unistd.h>

#define NET_SOCK_ALLOCATED 1

    typedef struct NetSocket NET_SOCK;
    typedef struct sockaddr_in NET_ADDR_IN;
    typedef struct sockaddr NET_ADDR;

    struct NetSocket {

        struct {
            B32 sys; // PF_INET or PF_UNIX
            B32 data; // SOCK_STREAM or SOCK_DGRAM
            B32 mode; // IPPROTO_TCP or IPPROTO_UDP
        } from;
#if defined(WIN32) || defined(WINDOWS_XP)
        SOCKET sock;
#else
        B32 sock;
#endif
        B8 * host;
        NET_ADDR_IN to;
        BIT status;
        STATUS(*open)(NET_SOCK * net);
        STATUS(*tie)(NET_SOCK * server);
        STATUS(*wait)(NET_SOCK * net, B32 max);
        STATUS(*join)(NET_SOCK * server, NET_SOCK * client);
        STATUS(*in)(NET_SOCK * client);
        void (*close)(NET_SOCK * net);
        void (*pop)(NET_SOCK * net);
    };

    NET_SOCK net_sock_std(B8U * host, B32U port);
    NET_SOCK * net_sock_push(B8U * host, B32U port);
    void net_sock_zero(NET_SOCK * net);
    STATUS net_sock_open(NET_SOCK * net);
    STATUS net_sock_tie(NET_SOCK * server);
    STATUS net_sock_wait(NET_SOCK * net, B32 max);
    STATUS net_sock_join(NET_SOCK * server, NET_SOCK * client);
    STATUS net_sock_in(NET_SOCK * client);
    STATUS net_sock_put(NET_SOCK * net);
    void net_sock_close(NET_SOCK * net);
    void net_sock_pop(NET_SOCK * net);

    void winsock_start();
    void winsock_stop();


#ifdef __cplusplus
}
#endif

#endif /* NET_SOCKET_H */

这是我的来源:

#include "net_socket.h"

void net_sock_function(NET_SOCK * net){
    if(net){
        net->open = net_sock_open;
        net->tie = net_sock_tie;
        net->wait = net_sock_wait;
        net->join = net_sock_join;
        net->in = net_sock_in;
        net->close = net_sock_close;
        net->pop = net_sock_pop;
    }
}

NET_SOCK net_sock_std(B8U * host, B32U port){
    NET_SOCK net;
    net_sock_zero(&net);
    if(host)net.host = strdup(host);
    if(port)net.to.sin_port = htons(port);
    bit_off(&net.status,NET_SOCK_ALLOCATED);
    return(net);
}

NET_SOCK * net_sock_push(B8U * host, B32U port){
    NET_SOCK * net = malloc(sizeof(NET_SOCK));
    net_sock_zero(net);
    if(host)net->host = strdup(host);
    if(port)net->to.sin_port = htons(port);
    bit_on(&net->status,NET_SOCK_ALLOCATED);
    return(net);
}

void net_sock_zero(NET_SOCK * net){
    if(net){
        winsock_start();
        net->from.data = SOCK_STREAM;
        net->from.mode = IPPROTO_TCP;
        if(is_win()){
            net->from.sys = AF_INET;
            net->to.sin_family = AF_INET;
        }
        else {
            net->from.sys = AF_UNIX;
            net->to.sin_family = AF_UNIX;
        }
        net->sock = -1;
        net->host = NULL;
        net->to.sin_addr.s_addr = htonl(INADDR_ANY);
        net->to.sin_port = 0;
        net_sock_function(net);
    }
}

STATUS net_sock_open(NET_SOCK * net){
    if(!net)return(Off);
    if( (net->sock = socket(net->from.sys,net->from.data,net->from.mode)) != -1)return(On);
    return(Off);
}

STATUS net_sock_tie(NET_SOCK * server){
    if(!server)return(Off);
    if(bind(server->sock,(NET_ADDR*)&server->to,sizeof(server->to)) != -1)return(On);
    return(Off);
}

STATUS net_sock_wait(NET_SOCK * net, B32 max){
    if(!net)return(Off);
    if(listen(net->sock,max) != -1)return(On);
    return(Off);
}

STATUS net_sock_join(NET_SOCK * server,NET_SOCK * client){
    if(!server || !client)return(Off);
    B32U clientLen = sizeof(client->to);
    while((client->sock = accept(server->sock,(NET_ADDR *)&client->to,&clientLen)) == -1)return(On);
    return(Off);
}

STATUS net_sock_in(NET_SOCK * client){
    if(!client)return(Off);
    if(connect(client->sock,(NET_ADDR *)&client->to,sizeof(client->to)) != -1)return(On);
    return(Off);
}

STATUS net_sock_put(NET_SOCK * net){
    if(!net)return(Off);

    return(Off);
}

void net_sock_close(NET_SOCK * net){
    if(is_win())closesocket(net->sock);
    else close(net->sock);
}

void net_sock_pop(NET_SOCK * net){
    if(net){
        if(net->host){
            free(net->host);
            net->host = NULL;
        }
        if(bit_is_on(net->status,NET_SOCK_ALLOCATED)){
            free(net);
            net = NULL;
        }
    }
}

void winsock_start() {
    if (is_win()) {
        WORD versionWanted = MAKEWORD(1, 1);
        WSADATA wsaData;
        WSAStartup(versionWanted, &wsaData);
        atexit(winsock_stop);
    }
}

void winsock_stop() {
    if (is_win()) {
        WSACleanup();
    }
}

最后我的主要是:

#include "net_socket.h"

void command_line(B32 c, B8 ** v, B8U ** host, B32U * port) {
    B32 i = 1;
    while (i < c) {
        switch (i) {
        case 1:
        {
            *port = atoi(v[i]);
        }
            break;
        case 2:
        {
            *host = v[i];
        }
            break;
        }
        i++;
    }
}

int main(int argc, char** argv) {
    B8U * host = NULL;
    B32U port = 50;
    command_line(argc, argv, &host, &port);
    NET_SOCK server = net_sock_std(NULL, port);
    if (server.open(&server)) {
        if (!host) {
            NET_SOCK client = net_sock_std("localhost", port);
            printf("server openned in %hu\n", server.to.sin_port);
            if (client.open(&client)) {
                printf("Server client openned in %hu", client.to.sin_port);
            }

            if (server.tie(&server) && server.wait(&server, 1)){
                printf("\nready\n");
            }

            while (server.join(&server, &client)){ // I can't get in search mode
                printf("searching\n");
            }
            client.pop(&client);

        } else {
            NET_SOCK client = net_sock_std(host, port);
            if (client.open(&client)) {
                printf("client openned in %s %hu\n", host, client.to.sin_port);
                while (!client.in(&client)) {
                    printf("trying to connect\n");
                }
                printf("bye server\n");
            }
        }
        server.close(&server);
    }
    server.pop(&server);
    return (EXIT_SUCCESS);
}

在我的朋友Jeremy的帮助下,我发现:(只是将服务器SOCK设置为关闭)

STATUS net_lock_socket(NET_SOCK * net, STATUS block) {
    if (!net || net->sock < 0) return Off;
#if defined(WIN32)
        unsigned long mode = block ? 0 : 1;
        return (ioctlsocket(net->sock, FIONBIO, &mode) == 0) ? On : Off;
#else
        int flags = fcntl(net->sock, F_GETFL, 0);
        if (flags == -1) return Off;
        flags = block ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
        return (fcntl(net->sock, F_SETFL, flags) == 0) ? On : Off;
#endif
}

1 个答案:

答案 0 :(得分:1)

首先,快速澄清 - 它不会listen()阻止,而是accept()listen()只是让操作系统知道您希望该套接字能够在将来接受传入的TCP连接;所以没有理由阻止它。

其次,要使accept()无阻塞,您需要首先使您在非阻塞时调用accept()的套接字 - 有关如何执行此操作的信息可用here

完成此操作后,如果检测到传入的TCP连接,则accept()将返回-1并将errno设置为EWOULDBLOCK,如果已经没有TCP连接等待它...所以为了知道何时适合在套接字上调用accept(),你可以在select()调用中的read fd-set中包含套接字。只要有传入的TCP连接存在,并且是时候调用accept()来处理它,accept-socket就会发出准备就绪的信号。