最近有个疑问,当客户端主动断开连接的时候srs服务器是怎么主动断开的,gdb跟踪。
我发现的有两种情况:
1.客户端主动断开连接情况:客户端连接服务器后,一直ret = do_publishing(source, &trd);这个函数哪里等待(代码如下),
当客户端主动断开后,就继续运行后面的 trd.stop(); 这个trd.stop()才是服务器断开客户端退出线程的关键地方。
int SrsRtmpConn::publishing(SrsSource* source)
{
int ret = ERROR_SUCCESS;
if ((ret = refer->check(req->pageUrl, _srs_config->get_refer_publish(req->vhost))) != ERROR_SUCCESS) {
srs_error("check publish_refer failed. ret=%d", ret);
return ret;
}
srs_verbose("check publish_refer success.");
if ((ret = http_hooks_on_publish()) != ERROR_SUCCESS) {
srs_error("http hook on_publish failed. ret=%d", ret);
return ret;
}
bool vhost_is_edge = _srs_config->get_vhost_is_edge(req->vhost);
if ((ret = acquire_publish(source, vhost_is_edge)) == ERROR_SUCCESS) {
// use isolate thread to recv,
// @see: https://github.com/ossrs/srs/issues/237
SrsPublishRecvThread trd(rtmp, req,
st_netfd_fileno(stfd), 0, this, source,
client_type != SrsRtmpConnFlashPublish,
vhost_is_edge);
srs_info("start to publish stream %s success", req->stream.c_str());
ret = do_publishing(source, &trd);
srs_trace("===========>>>>>>>>>>will trd.stop");
// stop isolate recv thread
trd.stop();
}
// whatever the acquire publish, always release publish.
// when the acquire error in the midlle-way, the publish state changed,
// but failed, so we must cleanup it.
// @see https://github.com/ossrs/srs/issues/474
// @remark when stream is busy, should never release it.
if (ret != ERROR_SYSTEM_STREAM_BUSY) {
release_publish(source, vhost_is_edge);
}
http_hooks_on_unpublish();
return ret;
}
2.客户端不正常退出后,服务器怎么断开连接的?
服务器会触发以写错误的信号 if (errno == EINTR),如下面代码
ssize_t st_writev(_st_netfd_t *fd, const struct iovec *iov, int iov_size,
st_utime_t timeout)
{
ssize_t n, rv;
size_t nleft, nbyte;
int index, iov_cnt;
struct iovec *tmp_iov;
struct iovec local_iov[_LOCAL_MAXIOV];
/* Calculate the total number of bytes to be sent */
nbyte = 0;
for (index = 0; index < iov_size; index++)
nbyte += iov[index].iov_len;
rv = (ssize_t)nbyte;
nleft = nbyte;
tmp_iov = (struct iovec *) iov; /* we promise not to modify iov */
iov_cnt = iov_size;
while (nleft > 0) {
if (iov_cnt == 1) {
if (st_write(fd, tmp_iov[0].iov_base, nleft, timeout) != (ssize_t) nleft)
rv = -1;
break;
}
if ((n = writev(fd->osfd, tmp_iov, iov_cnt)) < 0) {
if (errno == EINTR)
continue;
if (!_IO_NOT_READY_ERROR) {
rv = -1;
break;
}
} else {
if ((size_t) n == nleft)
break;
nleft -= n;
后面的代码省略
然后发生接下来下面代码的:return ERROR_SOCKET_WRITE;
int SrsStSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite)
{
int ret = ERROR_SUCCESS;
ssize_t nb_write = st_writev(stfd, iov, iov_size, send_timeout);
if (nwrite) {
*nwrite = nb_write;
}
// On success a non-negative integer equal to nbyte is returned.
// Otherwise, a value of -1 is returned and errno is set to indicate the error.
if (nb_write <= 0) {
// @see https://github.com/ossrs/srs/issues/200
if (nb_write < 0 && errno == ETIME) {
return ERROR_SOCKET_TIMEOUT;
}
return ERROR_SOCKET_WRITE;
}
send_bytes += nb_write;
return ret;
}
最后也回到了1.客户端主动断开连接的这一样步骤,运行 trd.stop(); 退出线程