我目前正在研究SIP示例应用程序。
我正在尝试在Unix上使用基于C的Socket编程进行注册。我已经成功地能够注册PJSIP,但是当我使用正常的套接字编程发送相同的参数时,我无法从服务器接收任何响应。
以下是源代码:
char *server = (char *)serverAddress; // First arg: server address/name
char *echoString = "Request msg REGISTER/cseq=46476 (tdta0x8857200)\r\nREGISTER sip:DOMAIN_NAME SIP/2.0\r\nVia: SIP/2.0/UDP 192.168.1.120:51648;rport;branch=z9hG4bKPjwEt4VvIVdjIJKRmEJbkidYDAu-zQbIqv\r\nMax-Forwards: 70\r\nFrom: <sip:USER_NAME@DOMAIN_NAME>;tag=epCBN7JXsQE1nnI5d5SOZe9a5ujRyI67\r\nTo: <sip:USER_NAME@DOMAIN_NAME>\r\nCall-ID: .5yYCqh2jEYdy5T4kxhzxwDYEkCO1XlD\r\nCSeq: 46476 REGISTER\r\nContact: <sip:USER_NAME@192.168.1.120:51648;ob>\r\nExpires: 300\r\nAllow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS\r\nAuthorization: Digest username=\"USER_NAME\", realm=\"asterisk\", nonce=\"3b63254c\", uri=\"sip:DOMAIN_NAME\", response=\"9e8fc78829d143a58fba5a79f6ad44fd\", algorithm=MD5\r\nContent-Length: 0";
size_t echoStringLen = strlen(echoString);
// Third arg (optional): server port/service
char *servPort = (char *)service;
// Tell the system what kind(s) of address info we want
struct addrinfo addrCriteria; // Criteria for address match
memset(&addrCriteria, 0, sizeof(addrCriteria)); // Zero out structure
addrCriteria.ai_family = AF_UNSPEC; // For the following fields, a zero value means
// Any address family "don't care"
addrCriteria.ai_socktype = SOCK_DGRAM; // Only datagram sockets
addrCriteria.ai_protocol = IPPROTO_UDP; // Only UDP protocol
// Get address(es)
struct addrinfo *servAddr; // List of server addresses
int rtnVal = getaddrinfo(server, servPort, &addrCriteria, &servAddr);
if (rtnVal != 0)
DieWithUserMessage("getaddrinfo() failed", gai_strerror(rtnVal));
// Create a datagram/UDP socket
int sock = socket(servAddr->ai_family, servAddr->ai_socktype,
servAddr->ai_protocol); // Socket descriptor for client
if (sock < 0)
DieWithSystemMessage("socket() failed");
// Send the string to the server
ssize_t numBytes = sendto(sock, echoString, echoStringLen, 0,
servAddr->ai_addr, servAddr->ai_addrlen);
if (numBytes < 0)
DieWithSystemMessage("sendto() failed");
else if (numBytes != echoStringLen)
DieWithUserMessage("sendto() error", "sent unexpected number of bytes");
// Receive a response
struct sockaddr_storage fromAddr; // Source address of server
// Set length of from address structure (in-out parameter)
socklen_t fromAddrLen = sizeof(fromAddr);
char buffer[100 + 1]; // I/O buffer
numBytes = recvfrom(sock, buffer, 100, 0,
(struct sockaddr *) &fromAddr, &fromAddrLen);
if (numBytes < 0)
DieWithSystemMessage("recvfrom() failed");
else if (numBytes != 100)
DieWithUserMessage("recvfrom() error", "received unexpected number of bytes");
// Verify reception from expected source
int value = SockAddrsEqual(servAddr->ai_addr, (struct sockaddr *) &fromAddr);
if (value == 0)
DieWithUserMessage("recvfrom()", "received a packet from unknown source");
freeaddrinfo(servAddr);
buffer[echoStringLen] = '\0'; // Null-terminate received data
printf("Received: %s\n", buffer); // Print the echoed string
close(sock);
exit(0);
当我尝试调试代码时,断点从recvfrom方法调用中消失,如下所示。
numBytes = recvfrom(sock, buffer, 100, 0, (struct sockaddr *) &fromAddr, &fromAddrLen);
提前感谢您的合作。
答案 0 :(得分:0)
如果您没有收到Registrar服务器的回复,则很可能是因为它无法理解您发送的REGISTER请求或将其作为重复拒绝。您可能需要更加复杂地了解如何构建REGISTER请求,而不是简单地发送硬编码字符串。
除了你可以尝试的一个显而易见的事情是将所需的\ r \ n \ r \ n添加到echoString的末尾。所有SIP请求都需要以双行换行结束标题部分,并且字符串中缺少该请求。
答案 1 :(得分:0)
recvfrom()
阻止,直到收到响应,除非您将套接字设置为非阻塞。更好的方法是使用select()
超时(如一秒或两秒)。然后更好的是将整个事物放入循环中,重复一些次数(例如三次或四次)。
请记住,UDP不保证您的数据报将被传递:完全取决于您何时等待足够长的时间并且需要再次尝试。
另外,请检查servAddr
getaddrinfo()
中设置的值是否合理。如果地址或端口号错误,您的数据包可能会无声地消失。
答案 2 :(得分:0)
如果您确认这是套接字问题,那么很容易跟踪。
但如果你不确定那么这个问题使用网络分析应用程序(wireshark)&amp;看到你发送的数据包&amp;接收。然后看看套接字问题。