spice-gtk网络读写数据

1、发送网络数据包

1.1、spice_channel_write函数:往通道中写数据

/* coroutine context */

static void spice_channel_write(SpiceChannel *channel, const void *data, size_t len)

{

#ifdef HAVE_SASL

if (channel->priv->sasl_conn) {

spice_channel_flush_sasl(channel, data, len);

return;

}

#endif

spice_channel_flush_wire(channel, data, len);

}

1.2、spice_channel_flush_wire函数:实现循环写入网络中

//将data指针的datalen长度的数据放到wire中

static void spice_channel_flush_wire(SpiceChannel *channel,

const void *data,

size_t datalen)

{

SpiceChannelPrivate *c = channel->priv;

const char *ptr = data;

size_t offset = 0;

GIOCondition cond;

while (offset < datalen) {

gssize ret;

if (c->has_error) return;

ret = spice_channel_flush_wire_nonblocking(channel, ptr+offset, datalen-offset, &cond);

if (ret == -1) {

if (cond != 0) {

// TODO: should use g_pollable_input/output_stream_create_source() in 2.28 ?

g_coroutine_socket_wait(&c->coroutine, c->sock, cond);

continue;

} else {

CHANNEL_DEBUG(channel, "Closing the channel: spice_channel_flush %d", errno);

c->has_error = TRUE;

return;

}

}

if (ret == 0) {

CHANNEL_DEBUG(channel, "Closing the connection: spice_channel_flush");

c->has_error = TRUE;

return;

}

offset += ret;

}

}

1.3、spice_channel_flush_wire_nonblocking函数:处理xxx_flush_wire()函数的非阻塞部分,它返回写入结果,并将在@cond中设置适当的位,以防写入函数阻塞。

static gint spice_channel_flush_wire_nonblocking(SpiceChannel *channel,

const gchar *ptr,

size_t len,

GIOCondition *cond)

{

SpiceChannelPrivate *c = channel->priv;

gssize ret;

g_assert(cond != NULL);

*cond = 0;

if (c->tls) {

ret = SSL_write(c->ssl, ptr, len);

if (ret < 0) {

ret = SSL_get_error(c->ssl, ret);

*cond = ssl_error_to_cond(ret);

ret = -1;

}

} else {

GError *error = NULL;

ret = g_pollable_output_stream_write_nonblocking(G_POLLABLE_OUTPUT_STREAM(c->out), ptr, len, NULL, &error);

if (ret < 0) {

if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {

*cond = G_IO_OUT;

} else {

CHANNEL_DEBUG(channel, "Send error %s", error->message);

}

g_clear_error(&error);

ret = -1;

}

}

return ret;

}

2、接收网络数据包

2.1、spice_channel_read函数:提供给外部调用,将通道中传输的数据读出来到data中,长度值为“len”字节的数据填充“data”缓冲区。如果连接关闭或出现未知错误,则返回0;如果错误,则小于0;如果成功,则返回长度

/*

* Fill the 'data' buffer up with exactly 'len' bytes worth of data

* Returns 0 if connection was closed or on unknown errors, <0 for error and

* length on success

*/

/* coroutine context */

static int spice_channel_read(SpiceChannel *channel, void *data, size_t length)

{

SpiceChannelPrivate *c = channel->priv;

gsize len = length;

int ret;

while (len > 0) {

if (c->has_error) return 0; /* has_error is set by disconnect(), return no error */

#ifdef HAVE_SASL

if (c->sasl_conn)

ret = spice_channel_read_sasl(channel, data, len);

else

#endif

ret = spice_channel_read_wire(channel, data, len);

if (ret < 0)

return ret;

g_assert(ret <= len);

len -= ret;

data = ((char*)data) + ret;

#if DEBUG

if (len > 0)

CHANNEL_DEBUG(channel, "still needs %" G_GSIZE_FORMAT, len);

#endif

}

c->total_read_bytes += length;

return length;

}

2.2、spice_channel_read_wire函数:cond信号读取数据,将数据放到data中,长度放到len

/*

* Read at least 1 more byte of data straight off the wire

* into the requested buffer.

*/

/* coroutine context */

static int spice_channel_read_wire(SpiceChannel *channel, void *data, size_t len)

{

SpiceChannelPrivate *c = channel->priv;

while (TRUE) {

gssize ret;

GIOCondition cond;

if (c->has_error) {

/* has_error is set by disconnect(), return no error */

return 0;

}

ret = spice_channel_read_wire_nonblocking(channel, data, len, &cond);

if (ret == -1) {

if (cond != 0) {

// TODO: should use g_pollable_input/output_stream_create_source() ?

g_coroutine_socket_wait(&c->coroutine, c->sock, cond);

continue;

} else {

c->has_error = TRUE;

return errno > 0 ? -errno : -EIO;

}

}

if (ret == 0) {

CHANNEL_DEBUG(channel, "Closing the connection: spice_channel_read() - ret=0");

c->has_error = TRUE;

return 0;

}

return ret;

}

}

2.3、spice_channel_read_wire_nonblocking函数:poll方式读取数据

static int spice_channel_read_wire_nonblocking(SpiceChannel *channel,

void *data,

size_t len,

GIOCondition *cond)

{

SpiceChannelPrivate *c = channel->priv;

gssize ret;

g_assert(cond != NULL);

*cond = 0;

if (c->tls) {

ret = SSL_read(c->ssl, data, len);

if (ret < 0) {

ret = SSL_get_error(c->ssl, ret);

*cond = ssl_error_to_cond(ret);

ret = -1;

}

} else {

GError *error = NULL;

ret = g_pollable_input_stream_read_nonblocking(G_POLLABLE_INPUT_STREAM(c->in),

data, len, NULL, &error);

if (ret < 0) {

if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {

*cond = G_IO_IN;

} else {

CHANNEL_DEBUG(channel, "Read error %s", error->message);

}

g_clear_error(&error);

ret = -1;

}

}

return ret;

}

猜你喜欢

转载自blog.csdn.net/cai742925624/article/details/128828837
gtk
今日推荐