您的位置:首页 > 理论基础 > 计算机网络

Ubuntu上 rtsp 服务器与客户端利用socket进行交互------创建了rtsp服务器(服务器端用tcp协议传输)

2021-09-01 17:02 1021 查看

代码功能

写了一个RTSP服务器:创建了TCP套接字(socket),并在RTSP服务器端创建了RTP、RTCP套接字(socket)

Ubuntu下VLC充当了RTSP客户端

参考

https://blog.csdn.net/weixin_42462202/article/details/99068041

1、测试代码

/*
* Author:Frank
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>

#define SERVER_PORT     8554
#define SERVER_RTP_PORT  55532
#define SERVER_RTCP_PORT 55533
#define BUF_MAX_SIZE    (1024*1024)

static int createTcpSocket()
{
int sockfd;
int on = 1;

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
return -1;

setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));

return sockfd;
}

static int createUdpSocket()
{
int sockfd;
int on = 1;

sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0)
return -1;

setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));

return sockfd;
}

static int bindSocketAddr(int sockfd, const char* ip, int port)
{
struct sockaddr_in addr;

addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip);

if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) < 0)
return -1;

return 0;
}

static int acceptClient(int sockfd, char* ip, int* port)
{
int clientfd;
socklen_t len = 0;
struct sockaddr_in addr;

memset(&addr, 0, sizeof(addr));
len = sizeof(addr);

clientfd = accept(sockfd, (struct sockaddr *)&addr, &len);
if(clientfd < 0)
return -1;

strcpy(ip, inet_ntoa(addr.sin_addr));
*port = ntohs(addr.sin_port);

return clientfd;
}

static char* getLineFromBuf(char* buf, char* line)
{
while(*buf != '\n')
{
*line = *buf;
line++;
buf++;
}

*line = '\n';
++line;
*line = '\0';

++buf;
return buf;
}

static int handleCmd_OPTIONS(char* result, int cseq)
{
sprintf(result, "RTSP/1.0 200 OK\r\n"
"CSeq: %d\r\n"
"Public: OPTIONS, DESCRIBE, SETUP, PLAY\r\n"
"\r\n",
cseq);

return 0;
}

static int handleCmd_DESCRIBE(char* result, int cseq, char* url)
{
char sdp[500];
char localIp[100];

sscanf(url, "rtsp://%[^:]:", localIp);

sprintf(sdp, "v=0\r\n"
"o=- 9%ld 1 IN IP4 %s\r\n"
"t=0 0\r\n"
"a=control:*\r\n"
"m=video 0 RTP/AVP 96\r\n"
"a=rtpmap:96 H264/90000\r\n"
"a=control:track0\r\n",
time(NULL), localIp);

sprintf(result, "RTSP/1.0 200 OK\r\nCSeq: %d\r\n"
"Content-Base: %s\r\n"
"Content-type: application/sdp\r\n"
"Content-length: %d\r\n\r\n"
"%s",
cseq,
url,
strlen(sdp),
sdp);

return 0;
}

static int handleCmd_SETUP(char* result, int cseq, int clientRtpPort)
{
sprintf(result, "RTSP/1.0 200 OK\r\n"
"CSeq: %d\r\n"
"Transport: RTP/AVP;unicast;client_port=%d-%d;server_port=%d-%d\r\n"
"Session: 66334873\r\n"
"\r\n",
cseq,
clientRtpPort,
clientRtpPort+1,
SERVER_RTP_PORT,
SERVER_RTCP_PORT);

return 0;
}

static int handleCmd_PLAY(char* result, int cseq)
{
sprintf(result, "RTSP/1.0 200 OK\r\n"
"CSeq: %d\r\n"
"Range: npt=0.000-\r\n"
"Session: 66334873; timeout=60\r\n\r\n",
cseq);

return 0;
}

static void doClient(int clientSockfd, const char* clientIP, int clientPort,
int serverRtpSockfd, int serverRtcpSockfd)
{
char method[40];
char url[100];
char version[40];
int cseq;
int clientRtpPort, clientRtcpPort;
char *bufPtr;
char* rBuf = malloc(BUF_MAX_SIZE);
char* sBuf = malloc(BUF_MAX_SIZE);
char line[400];

while(1)
{
int recvLen;

recvLen = recv(clientSockfd, rBuf, BUF_MAX_SIZE, 0);
if(recvLen <= 0)
goto out;

rBuf[recvLen] = '\0';
printf("---------------C->S--------------\n");
printf("%s", rBuf);

/* 解析方法 */
bufPtr = getLineFromBuf(rBuf, line);
if(sscanf(line, "%s %s %s\r\n", method, url, version) != 3)
{
printf("parse err\n");
goto out;
}

/* 解析序列号 */
bufPtr = getLineFromBuf(bufPtr, line);
if(sscanf(line, "CSeq: %d\r\n", &cseq) != 1)
{
printf("parse err\n");
goto out;
}

/* 如果是SETUP,那么就再解析client_port */
if(!strcmp(method, "SETUP"))
{
while(1)
{
bufPtr = getLineFromBuf(bufPtr, line);
if(!strncmp(line, "Transport:", strlen("Transport:")))
{
sscanf(line, "Transport: RTP/AVP;unicast;client_port=%d-%d\r\n",
&clientRtpPort, &clientRtcpPort);
break;
}
}
}

if(!strcmp(method, "OPTIONS"))
{
if(handleCmd_OPTIONS(sBuf, cseq))
{
printf("failed to handle options\n");
goto out;
}
}
else if(!strcmp(method, "DESCRIBE"))
{
if(handleCmd_DESCRIBE(sBuf, cseq, url))
{
printf("failed to handle describe\n");
goto out;
}
}
else if(!strcmp(method, "SETUP"))
{
if(handleCmd_SETUP(sBuf, cseq, clientRtpPort))
{
printf("failed to handle setup\n");
goto out;
}
}
else if(!strcmp(method, "PLAY"))
{
if(handleCmd_PLAY(sBuf, cseq))
{
printf("failed to handle play\n");
goto out;
}
}
else
{
goto out;
}

printf("---------------S->C--------------\n");
printf("%s", sBuf);
send(clientSockfd, sBuf, strlen(sBuf), 0);
}
out:
close(clientSockfd);
free(rBuf);
free(sBuf);
}

int main(int argc, char* argv[])
{
int serverSockfd;
int serverRtpSockfd, serverRtcpSockfd;
int ret;

serverSockfd = createTcpSocket();
if(serverSockfd < 0)
{
printf("failed to create tcp socket\n");
return -1;
}

ret = bindSocketAddr(serverSockfd, "0.0.0.0", SERVER_PORT);
if(ret < 0)
{
printf("failed to bind addr\n");
return -1;
}

ret = listen(serverSockfd, 10);
if(ret < 0)
{
printf("failed to listen\n");
return -1;
}

serverRtpSockfd = createUdpSocket();
serverRtcpSockfd = createUdpSocket();
if(serverRtpSockfd < 0 || serverRtcpSockfd < 0)
{
printf("failed to create udp socket\n");
return -1;
}

if(bindSocketAddr(serverRtpSockfd, "0.0.0.0", SERVER_RTP_PORT) < 0 ||
bindSocketAddr(serverRtcpSockfd, "0.0.0.0", SERVER_RTCP_PORT) < 0)
{
printf("failed to bind addr\n");
return -1;
}

printf("rtsp://127.0.0.1:%d\n", SERVER_PORT);

while(1)
{
int clientSockfd;
char clientIp[40];
int clientPort;

clientSockfd = acceptClient(serverSockfd, clientIp, &clientPort);
if(clientSockfd < 0)
{
printf("failed to accept client\n");
return -1;
}

printf("accept client;client ip:%s,client port:%d\n", clientIp, clientPort);

doClient(clientSockfd, clientIp, clientPort, serverRtpSockfd, serverRtcpSockfd);
}

return 0;
}
View Code

2、测试前提

具体步骤如下:

2.1、需要提前在ubuntu下安装vlc播放器:

sudo apt-get install vlc

2.2、目前虚拟机网络配置:

rtsp://127.0.0.1:8554
accept client;client ip:127.0.0.1,client port:35106
---------------C->S--------------
OPTIONS rtsp://127.0.0.1:8554 RTSP/1.0
CSeq: 2
User-Agent: LibVLC/2.2.2 (LIVE555 Streaming Media v2016.02.09)

---------------S->C--------------
RTSP/1.0 200 OK
CSeq: 2
Public: OPTIONS, DESCRIBE, SETUP, PLAY

---------------C->S--------------
DESCRIBE rtsp://127.0.0.1:8554 RTSP/1.0
CSeq: 3
User-Agent: LibVLC/2.2.2 (LIVE555 Streaming Media v2016.02.09)
Accept: application/sdp

---------------S->C--------------
RTSP/1.0 200 OK
CSeq: 3
Content-Base: rtsp://127.0.0.1:8554
Content-type: application/sdp
Content-length: 125

v=0
o=- 91630487295 1 IN IP4 127.0.0.1
t=0 0
a=control:*
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=control:track0
---------------C->S--------------
SETUP rtsp://127.0.0.1:8554/track0 RTSP/1.0
CSeq: 4
User-Agent: LibVLC/2.2.2 (LIVE555 Streaming Media v2016.02.09)
Transport: RTP/AVP;unicast;client_port=45400-45401

---------------S->C--------------
RTSP/1.0 200 OK
CSeq: 4
Transport: RTP/AVP;unicast;client_port=45400-45401;server_port=55532-55533
Session: 66334873

---------------C->S--------------
PLAY rtsp://127.0.0.1:8554 RTSP/1.0
CSeq: 5
User-Agent: LibVLC/2.2.2 (LIVE555 Streaming Media v2016.02.09)
Session: 66334873
Range: npt=0.000-

---------------S->C--------------
RTSP/1.0 200 OK
CSeq: 5
Range: npt=0.000-
Session: 66334873; timeout=60

---------------C->S--------------
TEARDOWN rtsp://127.0.0.1:8554 RTSP/1.0
CSeq: 6
User-Agent: LibVLC/2.2.2 (LIVE555 Streaming Media v2016.02.09)
Session: 66334873
View Code  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐