关于C语言中的套接字编程的几个问题

时间:2015-06-15 12:56:30

标签: c sockets

我对C:中的Telnet / TCP套接字编程有几个问题:

  1. 当我激活客户端以远程访问程序时,它表现正常但是如果我在程序运行时关闭终端,则发出的最后一个远程命令决定重复,直到程序终止,怎么办顶一下?

  2. 当我的程序到达套接字代码,即下面我声明的函数时,即使我没有打开客户端,我也无法再手动/本地操作我的程序。我有一个谷歌有这个问题,最好的结果似乎是与接受套接字命令阻止访问。注意:我曾尝试使用非阻塞套接字,但仍然没有运气。另请注意,即使远程终端被激活,我希望我的程序能够同时手动/本地操作,如果可能的话,如果远程终端启动时手动控制程序以反映远程终端的变化

  3. 最后,我希望能够输入一个单词或短语来激活命令,而不仅仅是单个字符。如果我输入一个单词而不是一个字符,我会得到一个多字符错误,如果我尝试双引号,它似乎没有响应任何事情,尽管成功编译。根据我所听到的,如果您使用C ++编程而不是C编程,则可以使用双引号,但是我听说可以使用单词在C中发出命令。

  4. 我在下面发布了我的套接字代码,我知道while(1)循环是一个问题,但这是目前唯一阻止它关闭连接的东西。另请注意,remotecommand函数在我的主程序中以无限循环的形式声明,但在运行声明的函数后,尽管关闭了连接,但没有运行任何代码。

    void sigchld_handler(int s)
    {
    while(waitpid(-1, NULL, WNOHANG) > 0);
    }
    
    // get sockaddr, IPv4 or IPv6:
    void *get_in_addr(struct sockaddr *sa)
    {
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }
    
    return &(((struct sockaddr_in6*)sa)->sin6_addr);
    }
    
    
    
    int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
    int rc;
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_storage their_addr; // connector's address information
    socklen_t sin_size;
    struct sigaction sa;
    int yes=1;
    char s[INET6_ADDRSTRLEN];
    int rv;
    char recv_client_msg[100];
    
    
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP
    
    if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }
    
    // loop throui_pgh all the results and bind to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->arotocol)) == -1) {
            perror("server: socket");
            continue;
        }
    
        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                sizeof(int)) == -1) {
            perror("setsockopt");
            exit(1);
        }
    
        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("server: bind");
            continue;
        }
    
        break;
    }
    
    if (p == NULL)  {
        fprintf(stderr, "server: failed to bind\n");
        return 2;
    }
    
    freeaddrinfo(servinfo); // all done with this structure
    
    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }
    
    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }
    
        int RemoteCommand(){  // main accept() loop
        sin_size = sizeof their_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
        if (new_fd == -1) {
            perror("accept");
        return(-1);  
        }
        //fcntl(sockfd, F_SETFL, O_NONBLOCK);
        //fcntl(new_fd, F_SETFL, O_NONBLOCK);
    
        inet_ntop(their_addr.ss_family,
            get_in_addr((struct sockaddr *)&their_addr),
            s, sizeof s);
        printf("server: got connection from %s\n", s);
    
        if (!fork()) { // this is the child process
        close(sockfd); // child doesn't need the listener
        if (send(new_fd, "Hello, world!", 13, 0) == -1)
        perror("send");         
    
    while(1) 
     {
       rc = read(new_fd, recv_client_msg, sizeof(recv_client_msg));
       if(write(new_fd,recv_client_msg, rc) <0 ) { printf("error writing to         stream socket\n"); }
       if(recv_client_msg[0]=='1') {commandSwitch(1,1);}
       if(recv_client_msg[0]=='2') {commandSwitch(1,2);}
       if(recv_client_msg[0]=='3') {commandSwitch(2,1);}
       if(recv_client_msg[0]=='4') {commandSwitch(2,2);}    
     }
        close(new_fd);
            exit(0);
        }
        close(new_fd);  // parent doesn't need this
        return(0);
    }   
    //end of socket setup 
    

    这是我第一次使用套接字,所以如果有人有解决方案,请尝试详细说明你的意思。

1 个答案:

答案 0 :(得分:3)

您需要实际检查read返回的内容。它会在出现错误时返回-1,并在正常关闭连接时返回0

由于您没有检查,您不会注意到连接已关闭或任何错误,只是尝试接收和接收,没有任何事情发生并一遍又一遍地使用相同的数据

正确处理的例子:

rc = read(...);

// At this point, we don't know if we have actually received anything

if (rc <= 0)
{
    if (rc == 0)
        printf("Connection closed in a nice way by the other end\n");
    else
        fprintf(stderr, "Error reading: %s\n", strerror(errno));

    // Do note that not *all* errors are actually fatal,
    // For example: If you have non-blocking sockets then you
    // could have `errno == EWOULDBLOCK` and that's okay, and
    // means you should try to receive again in a little while

    break;  // Break out of loop, let the connection be closed
}

// Now we *know* we have received something, process the data received
// To be more precise, we have received `rc` byes of data