代码功能
写了一个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:8554accept client;client ip:127.0.0.1,client port:35106---------------C->S--------------OPTIONS rtsp://127.0.0.1:8554 RTSP/1.0CSeq: 2User-Agent: LibVLC/2.2.2 (LIVE555 Streaming Media v2016.02.09)---------------S->C--------------RTSP/1.0 200 OKCSeq: 2Public: OPTIONS, DESCRIBE, SETUP, PLAY---------------C->S--------------DESCRIBE rtsp://127.0.0.1:8554 RTSP/1.0CSeq: 3User-Agent: LibVLC/2.2.2 (LIVE555 Streaming Media v2016.02.09)Accept: application/sdp---------------S->C--------------RTSP/1.0 200 OKCSeq: 3Content-Base: rtsp://127.0.0.1:8554Content-type: application/sdpContent-length: 125v=0o=- 91630487295 1 IN IP4 127.0.0.1t=0 0a=control:*m=video 0 RTP/AVP 96a=rtpmap:96 H264/90000a=control:track0---------------C->S--------------SETUP rtsp://127.0.0.1:8554/track0 RTSP/1.0CSeq: 4User-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 OKCSeq: 4Transport: RTP/AVP;unicast;client_port=45400-45401;server_port=55532-55533Session: 66334873---------------C->S--------------PLAY rtsp://127.0.0.1:8554 RTSP/1.0CSeq: 5User-Agent: LibVLC/2.2.2 (LIVE555 Streaming Media v2016.02.09)Session: 66334873Range: npt=0.000----------------S->C--------------RTSP/1.0 200 OKCSeq: 5Range: npt=0.000-Session: 66334873; timeout=60---------------C->S--------------TEARDOWN rtsp://127.0.0.1:8554 RTSP/1.0CSeq: 6User-Agent: LibVLC/2.2.2 (LIVE555 Streaming Media v2016.02.09)Session: 66334873
View Code