rtsp协议调试程序

最近碰到移植rtsp库到wince下,读不到数据,为了解决问题,写了一个小的rtsp客户端协议学习程序,实现基本的会话协议,OPTIONS,DESCRIBE,SETUP,PLAY等协议,将读取的数据存入到文件中去。程序代码贴在下面,这个代码能在ce和pc上跑。供大家分享下。

#ifdef _WIN32_WCE
#include "stdafx.h"
#endif

#ifndef _WIN32_WCE
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <commctrl.h>

#include <MMSystem.h>

#include <winsock2.h>

#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>

#ifdef _WIN32_WCE
#pragma comment(lib, "ws2.lib")
#else
#pragma comment(lib, "ws2_32.lib")
#endif

#define  PP_NAME "User-Agent:rtsp client(v1.0)"
#define  PP_CRLF "/r/n"

//测试之用

//打开连接
long InitSocket();

//关闭连接
long DeInitSocket();

//初始化tcp socket
long InitTCPSocket(int port);

//初始化udp socket
long InitUDPSocket(const char *ip, int port);

//取socket端口号
long GetSokcetPort(int sock, int *port);

//读取数据
long ReadSocket(int sock, char *buf, int len, int timeout);

//发送命令数据
long SendRTSPCmd(int sock, const char *cmd, const char *szparam);

//解析rtsp命令回应数据
long PraseRTSPCmd();
long PraseOptionCmd(const char *sz);
long PraseDescribeCmd(const char *sz);
long PraseSetupCmd(const char *sz, char *sess);
long PrasePlayCmd(const char *sz);
long GetResponseCode(const char *sz);  //取返回值

//
//字符串操作函数
static char* getLine(char* startOfLine);


//生成rtsp发送命令
char * GetRTSPCmd(const char *);
char * GetOptionCmd(char *url);
char * GetDescribeCmd(char *url);
char * GetPlayCmd(char *url, char *session, char *range);
char * GetSetupCmd(char *url, int port1, int port2);

char * GetReportCmd(char *);

//
//日志函数
long logwr(void *, int len);

//全局变量定义区
fd_set rfdsock;
//日志写入文件指针
FILE *fp = NULL;
//

//
//rtsp请求解析
long PraseURL(const char *url, char *szip, int *iport);
int _tmain(int argc, _TCHAR* argv[])
{
 int sockin, sc1, sc2;
 sockaddr_in addr;
 char *buf, *szcmd, *url;
 char szip[32];
 int nlen, iret, iport;
 int ip1, ip2;
 long lret;

 //初始化变量 
 FD_ZERO(&rfdsock);

 fp = fopen("1.txt", "w+");
 //分配缓冲区
 nlen = 10240;
 buf = (char*)malloc(nlen);

 //定义要连接的url
 //url = "rtsp://192.168.1.43:2554/realmp3.mp3";
 url = "rtsp://192.168.1.42/realmp3.mp3";
 //url = "rtsp://192.168.1.43/1.amr";
 //初始化sock
 InitSocket();

 //分析url请求,取出ip,端口
 lret = PraseURL(url, szip, &iport);


 //初始化与服务器连接的socket
 sockin = InitTCPSocket(0);

 //与服务器连接
 addr.sin_family = AF_INET;
 addr.sin_port = htons(iport);
 addr.sin_addr.s_addr = inet_addr(szip);
 iret = connect(sockin,(struct sockaddr*)&addr, sizeof addr);

 //发送option命令
 szcmd = GetOptionCmd(url);
 lret = SendRTSPCmd(sockin, "OPTIONS",szcmd);
 free(szcmd);

 lret = ReadSocket(sockin, buf, nlen,100);

 
 //发送DESCRIBE命令
 szcmd = GetDescribeCmd(url);
 lret = SendRTSPCmd(sockin, "DESCRIBE", szcmd);
 free(szcmd);
 lret = ReadSocket(sockin, buf,  nlen, 100);
 
 //解析Response
 lret = PraseDescribeCmd((const char*)buf);

 //创建客户端接收端口
 sc1 = InitUDPSocket(NULL, 6544);
 sc2 = InitUDPSocket(NULL, 6545);

 //将sock加入到要等待的队列
 
 FD_SET(sc1, &rfdsock );
 FD_SET(sc2, &rfdsock);


 lret = GetSokcetPort(sc1, &ip1);
 lret = GetSokcetPort(sc2, &ip2);

 //发送Setup命令,告诉服务器客户端的接受数据的端口
 szcmd = GetSetupCmd(url, ip1, ip2);
 //告诉服务器客户端的端口
 lret = SendRTSPCmd(sockin, "SETUP", szcmd);
 free(szcmd);
 lret = ReadSocket(sockin, buf, nlen, 100);
 //解析Response返回的命令串
 lret = PraseSetupCmd(buf, szip);

 char *session, *srange;
 session = szip;
 //发送PLAY命令
 srange  = "Range: npt=0.000-39.471/r/n";
 szcmd = GetPlayCmd(url, session, srange);
 lret = SendRTSPCmd(sockin, "PLAY", szcmd);
 free(szcmd);
 lret = ReadSocket(sockin, buf, nlen, 100);

 timeval tv;
 fd_set fr;

 int i;

 tv.tv_sec = 20;
 tv.tv_usec = 0;
 struct sockaddr_in addr2;
 int addrlen;
 addrlen = sizeof addr;

 //将数据写到文件中去
 FILE *ffp;
 ffp = fopen("1.mp3", "w+");

 //开始接受数据了
 while(true)
 {
  fr = rfdsock;
  lret  = select(0, &fr, NULL, NULL, &tv);

  if(lret == SOCKET_ERROR)
  {
   break;
  }
  else if(lret >0)
  {
   //判断是哪个socket可以读取数据了
   for(i = 0; i< 2;i ++)
   {
    if(FD_ISSET(rfdsock.fd_array[i], &fr)
     && FD_ISSET(rfdsock.fd_array[i], &rfdsock))
    {
     lret = recvfrom(rfdsock.fd_array[i], buf, nlen,0, (struct sockaddr*)&addr2, &addrlen );
     if(lret > 0 && ffp)
     {
      fwrite(buf, 1, lret, ffp);
     }
     else if(lret == SOCKET_ERROR)
     {
      break;
     }
    }
   }

  }
  else if(lret == 0)
   break;
 }
 fclose(ffp);

 //退出后的清理工作
 closesocket(sockin);
 closesocket(sc1);
 closesocket(sc2);

 fwrite("/r/nend", 1, 5, fp);
 fclose(fp);
 return 0;
}

long InitSocket()
{
 WSADATA ws;
 long lret  = -1;
 lret = WSAStartup(MAKEWORD(2,2), &ws);
 return 0;
}

long DeInitSocket()
{

 WSACleanup();
 return 0;
}

long InitTCPSocket( int port )
{
 long lret ;
 int sock;
 sockaddr_in addr;
 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

 //int flag = 1;
 //lret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&flag, sizeof flag);

 //addr.sin_family = AF_INET;
 //addr.sin_port = 0;
 //addr.sin_addr.s_addr = INADDR_ANY;
 //lret = bind(sock, (struct sockaddr*)&addr, sizeof addr);
 lret = sock;
 return lret;
}
#define   SIO_RCVALL                         _WSAIOW(IOC_VENDOR,1)  
#define   SIO_RCVALL_MCAST             _WSAIOW(IOC_VENDOR,2)  
#define   SIO_RCVALL_IGMPMCAST     _WSAIOW(IOC_VENDOR,3)  
#define   SIO_KEEPALIVE_VALS         _WSAIOW(IOC_VENDOR,4)  
#define   SIO_ABSORB_RTRALERT       _WSAIOW(IOC_VENDOR,5)  
#define   SIO_UCAST_IF                     _WSAIOW(IOC_VENDOR,6)  
#define   SIO_LIMIT_BROADCASTS     _WSAIOW(IOC_VENDOR,7)  
#define   SIO_INDEX_BIND                 _WSAIOW(IOC_VENDOR,8)  
#define   SIO_INDEX_MCASTIF           _WSAIOW(IOC_VENDOR,9)  
#define   SIO_INDEX_ADD_MCAST       _WSAIOW(IOC_VENDOR,10)  
#define   SIO_INDEX_DEL_MCAST       _WSAIOW(IOC_VENDOR,11)  
long InitUDPSocket(const char *ip,  int port )
{
 long lret;
 int sock;
 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 int flag = 1;
 lret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&flag, sizeof flag);

 sockaddr_in addr;

 addr.sin_family = AF_INET;
 addr.sin_port = port;
 if(ip)
  addr.sin_addr.s_addr = inet_addr(ip);
 else
  addr.sin_addr.s_addr = INADDR_ANY;
 lret = bind(sock, (struct sockaddr*)&addr, sizeof addr);
 //设置非堵塞通讯
 //u_long arg = 2;
 //lret = ioctlsocket(sock, SIO_LIMIT_BROADCASTS, &arg);

 lret = sock;
 return lret;
}

long GetSokcetPort( int sock, int *port )
{
 long lret = -1;
 sockaddr_in addr;
 int nlen;
 nlen = sizeof addr;

 addr.sin_port = 0;

 *port = 0;

 if(getsockname(sock, (struct sockaddr*)&addr, &nlen) < 0)
  lret = -1;
 else
 {
  lret = 0;
  *port = addr.sin_port;
 }

 return lret;
}

long ReadSocket(int sock,  char *buf, int len, int timeout )
{
 long lret ;
 int iret;
 fd_set fr;
 timeval tm;
 tm.tv_sec = timeout;
 tm.tv_usec = 0;

 FD_ZERO(&fr);
 fr.fd_count = 1;
 fr.fd_array[0] = sock;

 lret = select(sock, &fr, NULL, NULL, &tm);

 if(lret > 0)
 {
  lret = recv(sock, buf, len, 0);
  if(lret == SOCKET_ERROR)
  {
  
  }
  else if(lret > 0)
  {
   logwr((void*)buf, lret);
  }
 }
 
 return lret;
}

long SendRTSPCmd( int sock, const char *cmd, const char *szparam )
{
 long lret;
 int ilen;
 ilen = strlen(szparam);
 lret = send(sock, szparam, ilen,0);
 if(lret == SOCKET_ERROR)
 {
  lret = WSAGetLastError();
 }
 logwr((void *)szparam, ilen);
 return lret;
}

char * GetRTSPCmd( const char * szName)
{
 char *str = NULL;
 char const*  cmdFmt = NULL;
 if(!strcmp(szName, "OPTIONS"))
 {
  cmdFmt =
   "OPTIONS %s RTSP/1.0/r/n"
   "CSeq: %d/r/n"
   "%s"
   "%s"
#ifdef SUPPORT_REAL_RTSP
   REAL_OPTIONS_HEADERS
#endif
   "/r/n";
 }
 else if(!strcmp(szName, "ANNOUNCE"))
 {
   cmdFmt =
   "ANNOUNCE %s RTSP/1.0/r/n"
   "CSeq: %d/r/n"
   "Content-Type: application/sdp/r/n"
   "%s"
   "Content-length: %d/r/n/r/n"
   "%s";
 }
 else if(!strcmp(szName, "PLAY"))
 {
   cmdFmt =
   "PLAY %s RTSP/1.0/r/n"
   "CSeq: %d/r/n"
   "Session: %s/r/n"
   "%s"
   "%s"
   "%s"
   "%s"
   "/r/n";

 }
 else if(!strcmp(szName, "PAUSE"))
 {
   cmdFmt =
   "PAUSE %s RTSP/1.0/r/n"
   "CSeq: %d/r/n"
   "Session: %s/r/n"
   "%s"
   "%s"
   "/r/n";
 }
 else if(!strcmp(szName, "RECORD"))
 {
  cmdFmt =
   "RECORD %s%s%s RTSP/1.0/r/n"
   "CSeq: %d/r/n"
   "Session: %s/r/n"
   "Range: npt=0-/r/n"
   "%s"
   "%s"
   "/r/n";
 }
 else if(!strcmp(szName, "SET_PARAMETER"))
 {
   cmdFmt =
   "SET_PARAMETER %s RTSP/1.0/r/n"
   "CSeq: %d/r/n"
   "Session: %s/r/n"
   "%s"
   "%s"
   "Content-length: %d/r/n/r/n"
   "%s: %s/r/n";
 }
 else if(!strcmp(szName, "GET_PARAMETER"))
 {
   cmdFmt =
   "GET_PARAMETER %s RTSP/1.0/r/n"
   "CSeq: %d/r/n"
   "Session: %s/r/n"
   "%s"
   "%s"
   "Content-type: text/parameters/r/n"
   "Content-length: %d/r/n/r/n"
   "%s/r/n";
 }
 else if(!strcmp(szName, "TEARDOWN"))
 {
   cmdFmt =
   "TEARDOWN %s RTSP/1.0/r/n"
   "CSeq: %d/r/n"
   "Session: %s/r/n"
   "%s"
   "%s"
   "/r/n";
 }
 else if(!strcmp(szName, "DESCRIBE"))
 {
   cmdFmt =
   "DESCRIBE %s RTSP/1.0/r/n"
   "CSeq: %d/r/n"
   "%s"
   "%s"
   "%s"
 #ifdef SUPPORT_REAL_RTSP
   REAL_DESCRIBE_HEADERS
 #endif
   "/r/n";
 }
 else if(!strcmp(szName, "ANNOUNCE"))
 {
   cmdFmt =
  "ANNOUNCE %s RTSP/1.0/r/n"
  "CSeq: %d/r/n"
  "Content-Type: application/sdp/r/n"
  "%s"
  "Content-length: %d/r/n/r/n"
  "%s";
 }
 else if(!strcmp(szName, "SETUP"))
 {
  cmdFmt =
   "%s"
   "CSeq: %d/r/n"
   "%s"
   "%s"
   "%s"
   "%s"
   "/r/n";
 }
 str = (char*)cmdFmt;
 return str;
}

char * GetOptionCmd( char *url )
{
 int nlen, iret;
 char *ss;
 char *s = GetRTSPCmd("OPTIONS");
 
 nlen = strlen(s);
 iret = nlen + strlen(url) + strlen(PP_NAME) + 200;
 ss = (char*)malloc(iret);

 sprintf(ss, s, url, 1, PP_NAME, PP_CRLF);


 return ss;
}

char * GetDescribeCmd( char *url )
{
 int nlen, iret;
 char *ss;
 char *s = GetRTSPCmd("DESCRIBE");

 nlen = strlen(s);
 iret = nlen + strlen(url) + strlen(PP_NAME) + 200;
 ss = (char*)malloc(iret);

 sprintf(ss, s, url, 1, PP_NAME, PP_CRLF, PP_CRLF);

 return ss;
}
char * GetPlayCmd( char *url , char *session, char *range)
{
 int nlen, iret;
 char *ss;
 char *s = GetRTSPCmd("PLAY");

 nlen = strlen(s);
 iret = nlen + strlen(url) + strlen(PP_NAME) + 200;
 ss = (char*)malloc(iret);

 //char buf[128] = {0};
 //sprintf(buf, "Session: %s/r/n", session);

 sprintf(ss, s, url, 1, session, range, PP_NAME, PP_CRLF, PP_CRLF);

 return ss;
}

char * GetSetupCmd( char *url , int port1, int port2)
{
 int nlen, iret;
 char *ss;
 char *s = GetRTSPCmd("SETUP");

 nlen = strlen(s);
 iret = nlen + strlen(url) + strlen(PP_NAME) + 200;
 ss = (char*)malloc(iret);
 char buf[128] = {0};
 char buf2[128] = {0};
 if(port1 == 0)
  strcpy(buf, "Transport: RTP/AVP/TCP;unicast;interleaved=0-1");
 else
  sprintf(buf, "Transport: RTP/AVP;unicast;client_port=%d-%d/r/n", ntohs(port2), ntohs(port1));
 sprintf(buf2, "SETUP %s/streamid=0 RTSP/1.0/r/n", url);

 sprintf(ss, s, buf2, 1,  buf, PP_NAME, PP_CRLF, PP_CRLF);

 return ss;
}

long PraseURL( const char *url, char *szip, int *iport )
{
 long lret = -1;
 if(url)
 {
  //找到了rtsp这个标识符
  if(!_strnicmp(url, "rtsp://", 7))
  {
   //找ip
   char *s, *ss;
   s = (char*)url + strlen("rtsp://");
   ss = strchr(s, '/');

   strncpy(szip, s,  ss- s);
   szip[ss -s] = '/0';

   //查找下是否是有端口设置
   s = strchr(szip, ':');
   //有端口设置
   if(s)
   {
    ss = s;
    s ++;
    *iport = atoi(s);

    //同时修正ip地址
    szip[ss - szip] = '/0';
   }
   else
    *iport = 554;

   lret = 0;
  }
 }


 return lret;
}

long logwr( void *data, int len )
{
 long lret = -1;
 if(fp)
  lret = fwrite(data, 1, len, fp);

 return lret;
}


static char* getLine(char* startOfLine) {
 // returns the start of the next line, or NULL if none
 for (char* ptr = startOfLine; *ptr != '/0'; ++ptr) {
  // Check for the end of line: /r/n (but also accept /r or /n by itself):
  if (*ptr == '/r' || *ptr == '/n') {
   // We found the end of the line
   if (*ptr == '/r') {
    *ptr++ = '/0';
    if (*ptr == '/n') ++ptr;
   } else {
    *ptr++ = '/0';
   }
   return ptr;
  }
 }

 return NULL;
}

long GetResponseCode( const char *sz )
{
 long lret = -1;
 if(sz)
 {
  if(sscanf(sz, "%*s%u", &lret) != 1)
   ;
 }

 return lret;
}

long PraseDescribeCmd( const char *sz )
{
 long lret = -1;
 char *ss, *szst;
 szst = (char *)sz;
 int contentLength = -1;

 if(GetResponseCode(sz )== 200)
 {
  ss= getLine(szst);
  while(1)
  {
   ss = getLine(ss);
   if(ss == NULL)
    break;
   if (sscanf(ss, "Content-Length: %d", &contentLength) == 1
    || sscanf(ss, "Content-length: %d", &contentLength) == 1) {
     if (contentLength < 0) {
     }
   }
  }

 }

 return lret;
}

long PraseSetupCmd( const char *sz , char *sess)
{
 long lret = -1;
 char *ss, *szst;
 szst = (char *)sz;
 int contentLength = -1;
 
 if(GetResponseCode(sz )== 200)
 {
  ss= getLine(szst);
  while(1)
  {
   ss = getLine(ss);
   if(ss == NULL)
    break;
   if (sscanf(ss, "Session: %[^;]", sess) == 1)
   {
    lret = 1;
   }
  }

 }
 return lret;
}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/nxjbill/archive/2010/01/05/5137178.aspx

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值