Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SW_BUFFER_SIZE=8192 #4

Closed
wangchuan3533 opened this issue Jul 29, 2013 · 4 comments
Closed

SW_BUFFER_SIZE=8192 #4

wangchuan3533 opened this issue Jul 29, 2013 · 4 comments

Comments

@wangchuan3533
Copy link
Contributor

server.php

function my_onReceive($serv, $fd, $from_id, $data)
{
    //echo "Client:Data. fd=$fd|from_id=$from_id|data=$data\n";
    swoole_server_send($serv, $fd, $data);
    //echo "len=".strlen($data)."\n & data=\n$data\n";
}

client.php

<?php
$clients = array();
for($i = 0; $i < 1; $i++){
    $client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC); //同步阻塞
    $ret = $client->connect('127.0.0.1', 9501, 0.5, 0);
    if(!$ret)
    {
        echo "Over flow. errno=".$client->errCode;
        die("\n");
    }
    $clients[] = $client;
}
sleep(1);
while (1) {
    foreach ($clients as $client) {
        $buf = "";
        for ($i = 0; $i < 8192; $i++) {
            $buf .= chr(rand(0, 255));
        }
        echo "before len=" . strlen($buf) . "\n";
        $client->send($buf);
        $data = $client->recv(8192, 0);
        echo "after len=" . strlen($data) . "\n";
        if (strcmp($buf, $data) != 0) {
            die("mismatch");
        }
    }
    sleep(1);
}

client端结果($client->recv(8192, 1)也是同样的结果):

before len=8192
after len=0
mismatch

@wangchuan3533
Copy link
Contributor Author

查看了作者的代码,找到了问题所在
在服务器端,swServer_poll_onReceive_no_buffer调用swRead函数,数据长度刚好等于len,于是swRead函数会设置errno=EAGAIN,而swServer_poll_onReceive_no_buffer收到这个EAGAIN后会重新调用swRead,而swRead返回0,这时swServer_poll_onReceive_no_buffer就会认为socket已经断开,关闭相应的socket。

Base.c

SWINLINE int swRead(int fd, char *buf, int len)
{
    int n = 0, nread;

    while (1)
    {
        nread = read(fd, buf + n, len - n);
        //遇到错误
        if (nread < 0)
        {
            //中断
            if (errno == EINTR)
            {
                continue;
            }
            //出错了
            else
            {
                if (errno != EAGAIN)
                {
                    sw_errno = -1; //异常
                }
                break;
            }
        }
        //连接已关闭
        else if (nread == 0)
        {
            sw_errno = ECONNRESET;
            return 0;
        }
        else
        {
            n += nread;
            //内存读满了,还可能有数据
            if (n == len)
            {
                sw_errno = EAGAIN;
                break;
            }
            //已读完
            else
            {
                sw_errno = 0;
                continue;
            }
        }
    }
    return n;
}

Server.c

static int swServer_poll_onReceive_no_buffer(swReactor *reactor, swEvent *event)
{
    int ret, n;
    swServer *serv = reactor->ptr;
    swFactory *factory = &(serv->factory);
    swEventData buf;

    n = swRead(event->fd, buf.data, SW_BUFFER_SIZE);
    if (n < 0)
    {
        swTrace("swRead error: %d\n", errno);
        return SW_ERR;
    }
    else if (n == 0)
    {
        swTrace("Close Event.FD=%d|From=%d\n", event->fd, event->from_id);
        return swServer_close(serv, event);
    }
    else
    {
        swTrace("recv: %s|fd=%d|len=%d\n", buf.data, event->fd, n);
        buf.info.fd = event->fd;
        buf.info.len = n;
        buf.info.from_id = event->from_id;

        ret = factory->dispatch(factory, &buf);
        //处理数据失败,数据将丢失
        if (ret < 0)
        {
            swWarn("factory->dispatch fail\n");
        }
        if (sw_errno == SW_OK)
        {
            return ret;
        }
        //缓存区还有数据没读完,继续读,EPOLL的ET模式
        else if (sw_errno == EAGAIN)
        {
            ret = swServer_poll_onReceive_no_buffer(reactor, event);
        }
        return ret;
    }
    return SW_OK;
}

@shenzhe
Copy link
Member

shenzhe commented Jul 31, 2013

嗯, 连接关闭这块的逻辑需要做个EAGAIN判断了。

@matyhtf
Copy link
Member

matyhtf commented Aug 2, 2013

此bug已修复。接收的数据长度恰好等于BUFER_SIZE时会触发Close.

@matyhtf matyhtf closed this as completed Aug 2, 2013
@wangchuan3533
Copy link
Contributor Author

好的,我看看,谢谢

2013/8/2 Tianfeng notifications@github.com

此bug已修复。接收的数据长度恰好等于BUFER_SIZE时会触发Close.


Reply to this email directly or view it on GitHubhttps://github.com//issues/4#issuecomment-21984183
.

@diida diida mentioned this issue Jul 28, 2015
@benzhan benzhan mentioned this issue Jan 8, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants