c#socket编程关于阻塞侦听的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c#socket编程关于阻塞侦听的问题相关的知识,希望对你有一定的参考价值。

这是侦听client连接的循环,为什么只要我client连接一次后,也就是这个循环完整的执行一次后,我的client应该是被sd.close();关闭了,但是这个循环就变成真正的死循环了,没有if(sd.connected)的语句控制了.为什么已经关闭了socket连接,这个值还为真呢?还是其他的问题?

1.首先将标志位设为Non-blocking模式,准备在非阻塞模式下调用connect函数
2.调用connect,正常情况下,因为TCP三次握手需要一些时间;而非阻塞调用只要不能立即完成就会返回错误,所以这里会返回EINPROGRESS,表示在建立连接但还没有完成。
3.在读套接口描述符集(fd_set rset)和写套接口描述符集(fd_set
wset)中将当前套接口置位(用FD_ZERO()、FD_SET()宏),并设置好超时时间(struct
timeval *timeout)
4.调用select( socket, &rset, &wset, NULL, timeout )
返回0表示connect超时
如果你设置的超时时间大于75秒就没有必要这样做了,因为内核中对connect有超时限制就是75秒。
网络编程中socket的分量我想大家都很清楚了,socket也就是套接口,在套接口编程中,提到超时的概念,我们一下子就能想到3个:发送超时,接收超时,以及select超时(注:
select函数并不是只用于套接口的,但是套接口编程中用的比较多),在connect到目标主机的时候,这个超时是不由我们来设置的。不过正常情况下这个超时都很长,并且connect又是一个阻塞方法,一个主机不能连接,等着connect返回还能忍受,你的程序要是要试图连接多个主机,恐怕遇到多个不能连接的主机的时候,会塞得你受不了的。我也废话少说,先说说我的方法,如果你觉得你已掌握这种方法,你就不用再看下去了,如果你还不了解,我愿意与你分享。本文是已在Linux下的程序为例子,不过拿到Windows中方法也是一样,无非是换几个函数名字罢了。
Linux中要给connect设置超时,应该是有两种方法的。一种是该系统的一些参数,这个方法我不讲,因为我讲不清楚:P,它也不是编程实现的。另外一种方法就是变相的实现connect的超时,我要讲的就是这个方法,原理上是这样的:
1.建立socket
2.将该socket设置为非阻塞模式
3.调用connect()
4.使用select()检查该socket描述符是否可写(注意,是可写)
5.根据select()返回的结果判断connect()结果
6.将socket设置为阻塞模式(如果你的程序不需要用阻塞模式的,这步就省了,不过一般情况下都是用阻塞模式的,这样也容易管理)
参考技术A 本来就是一直循环啊,你又没有退出来,你可以这样写
bool flag = true;
while (flag)

try

if (SD.Connected)



else

SD.Close();
flag = false;


catch

SD.Close();
flag = false;


本回答被提问者采纳
参考技术B Close之后,可以加break

ZMQ:socket_send/recv 阻塞

【中文标题】ZMQ:socket_send/recv 阻塞【英文标题】:ZMQ: socket_send/recv blocking 【发布时间】:2013-08-23 16:38:09 【问题描述】:

所以我试图在 Python 中的 ZMQ 和 C/C++ 扩展中的 ZMQ 之间建立一些简单的通信。 Python 设置上下文,绑定一个 inproc 套接字,并将上下文和套接字名称传递给扩展。扩展设置自己的套接字、连接和侦听消息。然后 Python 发送一个标题,然后将字典的字符串表示形式发送到扩展。使用 REQ/REP 套接字的非常简单的东西。但是,由于某种原因,我似乎找不到,对 socket.send 的调用被阻塞,并且扩展永远不会超过对 zmq_recv 的调用。我有一个测试环境,其中播放的场景几乎完全相同,但套接字不会阻塞,并且我已经对代码进行了三次检查,它应该以相同的方式工作。

Python:

import zmq
import cppextension
# No lectures about using threading please. I'm restricted to, in essence
# using this function because of the code base I'm working with.
from thread import start_new_thread

socket = self.zmq_context.socket(zmq.REQ)
socket_name = "inproc://agl"
socket.bind(socket_name)
t = start_native_thread(cppextension.actor,
                        (self.zmq_context, socket_name))

test_send = "foo": 1, "bar": 2
# BLOCKS ON THIS LINE VVVVV
socket.send("TEST", flags=zmq.SNDMORE)
socket.send(str(test_send))
socket.recv()
socket.send("STOP")

C/C++:

// Originally these used std::basic_string<Py_UNICODE> but I reverted
// back to normal std::string so I can use a JSON parsing library.
typedef string pystring;
typedef char pystring_t;

extern "C" PyObject *
actor(PyObject *self, PyObject *args) 
    PyObject *py_context, *py_connect_to;
    PyThreadState *_save;
    void *context;
    char *connect_to;
    void *socket;
    int rc;

    if(!PyArg_ParseTuple(args, "OO", &py_context, &py_connect_to)) 
        PyErr_SetString(PyExc_TypeError, "Expected two arguments (ZMQ context, name of socket to connect to)");
        return NULL;
    
    py_context = PyObject_GetAttrString(py_context, "_handle");
    if(py_context == NULL) 
        PyErr_SetString(PyExc_TypeError, "Could not get '_handle' from context");
        return NULL;
    
    if(!PyInt_Check(py_context)) 
        PyErr_SetString(PyExc_TypeError, "_handle was not an integer");
        return NULL;
    
    context = (void*)PyInt_AsLong(py_context);
    connect_to = new char[PyString_Size(py_connect_to) + 1];
    strcpy(connect_to, PyString_AsString(py_connect_to));
    _save = PyEval_SaveThread();

    //
    // GIL-less operation BEGIN
    // ** WARNING: Do NOT call any functions that begin with 'Py', or touch any
    //    data structures that begin with 'Py' while in this section. It *WILL*
    //    blow up the Python interpreter.
    //
    socket = zmq_socket(context, ZMQ_REP);
    rc = zmq_connect(socket, connect_to);

    pystring TEST("TEST");
    pystring STOP("STOP");
    pystring SUCCESS("SUCCESS");
    pystring FAILURE("FAILURE");

    if(rc == 0) 
        int going = 1;
        // Should be able to hold a full megabyte of text, which should be enough
        // for any message being passed in.
        // Is there a way to query size of the incoming message...?
        char buffer[1000000];
        while(going) 
            // BLOCKS ON THIS LINE VVVVVV
            int size = zmq_recv(socket, buffer, 1000000, 0);
            if(size == -1) 
                // ERROR
                continue;
            
            // Assume we don't get larger than 1MB of data. Should put a
            // check around this at some point, but not right now.
            buffer[size] = 0;

            pystring fullmsg(buffer);
            cout << "ZMQ RECIEVED: " << fullmsg << endl;
            if(fullmsg == TEST) 
                size = zmq_recv(socket, &buffer, 1000000, 0);
                if(size != -1) 
                    buffer[size] = 0;
                    pystring json_fullmsg(buffer);
                    cout << "ZMQ JSON: " << json_fullmsg << endl;
                    contacts.add(json_fullmsg);
                    zmq_send(socket, SUCCESS.c_str(), SUCCESS.size() + 1, 0);
                
                else 
                    zmq_send(socket, FAILURE.c_str(), FAILURE.size() + 1, 0);
                
            
            else if(fullmsg == STOP) 
                going = 0;
                zmq_send(socket, SUCCESS.c_str(), SUCCESS.size() + 1, 0);
            
        
    
    else 
        // ERROR
        int err = zmq_errno();
        switch(err) 
        case EINVAL:
            cout << "ZMQ CONNECT ERR: " << "Endpoint supplied is invalid" << endl;
            break;
        default:
            cout << "ZMQ CONNECT ERR: " << err << endl;
            break;
        
    
    zmq_close(socket);
    //
    // GIL-less operation END
    //

    PyEval_RestoreThread(_save);
    Py_INCREF(Py_None);
    return Py_None;

非常感谢任何帮助弄清楚这里发生了什么。

编辑:另请注意,此代码将在 gevent 已对标准库进行猴子补丁的环境中运行。这是我使用 thread.start_new_thread 的部分原因,因为它是在猴子补丁发生之前保存的,我想要一个真正的线程而不是绿色线程。

【问题讨论】:

不是说它解决了你的问题,而是 Python 使用“#”表示 cmets,而不是“//”。 噢!当我添加这些 cmets 时,可能是在用 C/C++ 术语思考。谢谢,修好了。 他们使用相同的 zmqlib 版本吗? pythons zmqlib是pip编译成扩展的吗? 不是pip编译的,libzmq和pyzmq是我们自己编译的。 Python 和 C/C++ 代码都使用相同的版本。事实上,我什至无法在导入 zmq 之前导入 cppextension,因为我会收到一个 ImportError 抱怨由于未加载库而找不到符号(zmq_socket 等):) 如果您改用tcp: 传输,您会遇到同样的问题吗? inproc 要求在尝试连接之前完成绑定,而tcp 更宽容。 【参考方案1】:

两件事,

因为您在修改后的版本中使用 req/rep,所以“send,send,recv,send...”将 不行。 send/recv 都必须以“锁步”方式工作(send,recv,send,revc。)

ZMQ_NOBLOCK 将引发 EAGAIN 异常,这可能意味着“套接字连接 未完成,请稍后再回来。”尝试在绑定后放置一个定时器/睡眠 发送/接收。这就是导致“资源暂时不可用”消息的原因。

希望对你有帮助

先生。开关

【讨论】:

【参考方案2】:

不确定这会有所帮助,但这里是:

您确定send() 会阻止吗,这不仅仅是永远得不到回复的问题吗?您可以使用ZMQ_NOBLOCK 调用send() 并查看是否引发异常。如果是,则确实 send() 未能将消息排入队列。 您是否考虑过PAIR 套接字而不是REQ/REP? The guide recommends this 用于inproc 线程之间的通信。

【讨论】:

通过使用 zmq.DONTWAIT 作为标志的 socket.send 命令,我将“资源暂时不可用”打印到控制台。稍微改变一下,以便 Python 使用 REP 而 C/C++ 使用 REQ,然后在发送 TEST 数据之前接收一条消息,我得到“连接被拒绝”。我在 C/C++ 端看到了 EAGAIN 和 EFSM 错误。 @Freezeburn。好的,PAIR 插座呢? 不幸的是,他们似乎什么也没做。它的行为仍然与我使用 REQ/REP 套接字完全相同。

以上是关于c#socket编程关于阻塞侦听的问题的主要内容,如果未能解决你的问题,请参考以下文章

ZMQ:socket_send/recv 阻塞

socket 客户端编程:非阻塞式连接,错误判断及退出重连

非阻塞socket总结

什么是socket网络编程

linux网络编程中阻塞和非阻塞socket的区别

socket编程:I/O模型