为什么我的C套接字服务器不接收数据

时间:2015-02-17 05:51:45

标签: c sockets actionscript

我已经设置了一个非常简单的C套接字服务器,有两个文件。

main.c中:

#include "socket_server.h"
#include "main.h"

int main (int argc, char* argv[])
{
    start_socket_server(SOCKET_SERVER_PORT);

    while (1)
    { 
        update_clients();
    }
    return 0;
}

socket_server.c:

#include "socket_server.h"

int listen_fd, fdmax, newfd, nbytes, i, j, k;
char buf[256];
fd_set master;
fd_set read_fds;
struct timeval tv;

void start_socket_server(int port)
{
    struct sockaddr_in servaddr;

    FD_ZERO(&master);
    FD_ZERO(&read_fds);
    bzero( &servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htons(INADDR_ANY);
    servaddr.sin_port = htons(port);

    tv.tv_sec = 0;
    tv.tv_usec = 100;

    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
    listen(listen_fd, 10);

    FD_SET(listen_fd, &master);
    fdmax = listen_fd;
}

void update_clients()
{
    read_fds = master;
    select(fdmax+1, &read_fds, NULL, NULL, &tv);

    for(i = 0; i<= fdmax; i++)
    {
        if (FD_ISSET(i, &read_fds))
        {
            if (i == listen_fd)  //new connection
            {
                newfd = accept(listen_fd, (struct sockaddr *) NULL, NULL);

                if (newfd != -1)
                {
                    fprintf(stderr, "New connection!");
                    FD_SET(newfd, &master);

                    if (newfd > fdmax) {
                        fdmax = newfd;
                    }
                }
            } else {
                nbytes = recv(i, buf, sizeof buf, 0);
                if(nbytes <= 0)
                {
                    fprintf(stderr, "Dead");
                    close(i);
                    FD_CLR(i, &master);
                } else {
                    for(j = 0; j <= fdmax; j++)
                    {
                        if(FD_ISSET(j, &master))
                        {
                            if(j != listen_fd && j != i)
                            {
                                fprintf(stderr, "%s", buf);
                            }
                        }
                     }
                }
            }
        }
    }
}

然后我有一个简单的flash文件连接到它,并带有以下actionscript:

var socket = new XMLSocket;

socket.connect("12.34.56.78", 8080);

socket.onConnect = function(status) {
    if(status) {
        trace("connected");
        socket.writeUTF("Hello!");
        socket.flush();
    } else {
        trace("couldn't connect");
    }
};

如果我运行服务器,那么我的动作脚本,我希望如下:

  1. 服务器坐着等待
  2. Flash文件启动
  3. 服务器说“新连接!”和flash文件说“已连接”
  4. 服务器说“你好!”。
  5. 只有1-3发生。 “你好!”永远不会输出到我的终端。事实上,我可以告诉这个块:

    nbytes = recv(i, buf, sizeof buf, 0);
    if(nbytes <= 0)
    {
        fprintf(stderr, "Dead");
        close(i);
        FD_CLR(i, &master);
     } else {
        for(j = 0; j <= fdmax; j++)
        {
            if(FD_ISSET(j, &master))
            {
                if(j != listen_fd && j != i)
                {
                     fprintf(stderr, "%s", buf);
                }
             }
         }
    }
    

    根本不执行(除非我关闭我的Flash文件并且服务器打印“Dead”。

    发生了什么事?为什么我看不到从闪存发送的数据?我已设法将数据发送到闪存,但我无法接收任何FROM。这也是从闪存中运行的,因此在此阶段无需担心策略文件。

1 个答案:

答案 0 :(得分:1)

您需要将所有套接字设置为非阻塞。例如,

void start_socket_server(int port)
{
    struct sockaddr_in servaddr;
    int val;

    FD_ZERO(&master);
    FD_ZERO(&read_fds);
    bzero( &servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htons(INADDR_ANY);
    servaddr.sin_port = htons(port);

    tv.tv_sec = 0;
    tv.tv_usec = 100;

    listen_fd = socket(AF_INET, SOCK_STREAM, 0);

    if (-1 == ioctl(listen_fd, FIONBIO, (val = 1, &val)))
    {
        perror("ioctl failed!\n");
        goto ERROR;  /* TODO: or however else you want to deal with errors */
    }

    bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
    listen(listen_fd, 10);

    FD_SET(listen_fd, &master);
    fdmax = listen_fd;
}

...

    if (i == listen_fd)  //new connection
    {
        newfd = accept(listen_fd, (struct sockaddr *) NULL, NULL);

        if (newfd != -1)
        {
            int val;

            fprintf(stderr, "New connection!");

            if (-1 == ioctl(newfd, FIONBIO, (val = 1, &val)))
            {
                perror("ioctl failed!\n");
                goto ERROR;  /* TODO: or however else you want to deal with errors */
            }

            FD_SET(newfd, &master);

            if (newfd > fdmax) {
                fdmax = newfd;
            }
        }
    } else {
          nbytes = recv(i, buf, sizeof buf, 0);
            if(nbytes <= 0)
            {
                fprintf(stderr, "Dead");
                close(i);
                FD_CLR(i, &master);
            } else {
                fprintf(stdout, "Received %d bytes: '%s'\n", nbytes, buf);
            }
        }

在最初创建它之后,你也应该在你的主侦听套接字上执行此操作,这样你就不会陷入以某种方式接受()的调用。

此外,您输出读入数据的方式没有多大意义。如最初发布的那样,只有在建立了多个客户端连接时,代码才会打印出来。然后,当读入数据时,它将打印N - 1次,其中N是当前客户端连接的数量。