I found that the behavior of iOS socket "sendto" interface was different from android or linux kernel. When we call "sendto",we start wireshark capture at the same time . But we can't find the capture data immediately. We make a test that we continuously sending 332 bytes by "sendto" per 40ms interval.And we found that all data packets was send to the network in a short central time instead of a 40MS(or above) intervals. We doubt that the ios kernal made some change for udp.Also it may calls audio delay about 900-1000ms.
I have test in iphone 5s & iphone 6,iOS 10 or 11 by demo use "sendto" api
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/types.h>
int sSock = socket(AF_INET,SOCK_DGRAM,0);
struct sockaddr_in localAddr;
localAddr.sin_family = AF_INET;
localAddr.sin_port = htons(1001);
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sSock, (struct sockaddr*)&localAddr, sizeof(localAddr)) < 0)
{
NSLog(#"bind error");
return;
}
struct sockaddr_in sendAddr;
sendAddr.sin_family = AF_INET;
sendAddr.sin_port = htons(21000);
inet_pton(AF_INET, "114.190.105.220", &sendAddr.sin_addr);
char sendBuf[332] = {0};
//unsigned char service_type = 0xe0 | IPTOS_LOWDELAY | IPTOS_RELIABILITY;
int service_type = 0x10;
int priority = 6;
//if(setsockopt(sSock, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority))<0)
if(setsockopt(sSock,IPPROTO_IP,IP_TOS,(void*)(&service_type),sizeof(service_type)) < 0)
{
NSLog(#"setsockopt failed1,error[%s]",strerror(errno));
}
while(true)
{
sendto(sSock, sendBuf, sizeof(sendBuf), 0, (struct sockaddr*)&sendAddr, sizeof(sendAddr));
time_t timeNow;
time(&timeNow);
struct tm tmNow;
struct timeval tvNow;
localtime_r(&timeNow,&tmNow);
gettimeofday(&tvNow, NULL);
char sTime[256] = {0};
snprintf(sTime, sizeof(sTime)-1, "%04d%02d%02d %02d%02d%02d.%d",tmNow.tm_year+1900,tmNow.tm_mon,tmNow.tm_mday,tmNow.tm_hour,tmNow.tm_min,tmNow.tm_sec,tvNow.tv_usec/1000);
NSLog(#"[%s]interval 40ms send",sTime);
usleep(40*1000);
}
all data packets was send to the network in a short central time instead of a 40MS(or above) intervals.
all packets send at once,wireshark capture like this:
No. Time Protocol
819 41.439392 H264
820 41.439617 H264
821 41.439819 H264
Related
I want to send/receive data from a device via UDP. The device acts as a server and if I send it a value it sends me some values back. First I write a little python code which works without any problems:
import socket
import time
UDP_IP = "192.168.42.33"
UDP_PORT = 5004
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('',UDP_PORT))
while True:
MESSAGE = input('Write new message: ')
sock.sendto(bytes.fromhex(MESSAGE), (UDP_IP, UDP_PORT))
time.sleep(0.1)
data, addr = sock.recvfrom(1076)
a = len(data)
print ("Byte: ", data.hex()[46], data.hex()[47])
I can write a value to a register with this script and get an array with all updated register values from the device back. I write an equal program in c++:
#pragma once
#pragma comment(lib, "Ws2_32.lib")
#include <sdkddkver.h>
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string>
#define SCK_VERSION2 0x0202
#define BUFLEN 2048
using namespace std;
int main()
{
int inputI;
long SUCCESSFUL;
WSAData WinSockData;
WORD DLLVersion;
SOCKET sock;
char msg_input[] = { 0x60, 0x01, 0x00, 0x00}; //Write REG mode, 1 byte
char* SU_IP = "192.168.42.33"; //IP Address of Scanner Unit
u_short SU_PORT = 5004; //Port of Scanner Unit
SOCKADDR_IN ADDRESS;
char buf[BUFLEN];
int slen = sizeof(ADDRESS);
DLLVersion = MAKEWORD(2, 1);
SUCCESSFUL = WSAStartup(DLLVersion, &WinSockData);
sock = socket(AF_INET, SOCK_DGRAM, 0);
ADDRESS.sin_addr.s_addr = inet_addr(SU_IP);
ADDRESS.sin_family = AF_INET;
ADDRESS.sin_port = htons(SU_PORT);
connect(sock, (SOCKADDR*)&ADDRESS, sizeof(ADDRESS));
while (1)
{
cout << "Adresse des Registers (hex): ";
cin >> hex >> inputI;
msg_input[2] = inputI;
cout << "Wert des Registers (hex): ";
cin >> hex >> inputI;
msg_input[3] = inputI;
send(sock, msg_input, sizeof(msg_input), NULL);
//recv(sock, buf, BUFLEN, 0);
}
}
I am able to sent values and the device sends its register values back so the communication works (I checked this with wireshark). But I can't receive the data in my program. I oncomment the recv function because the program gets stuck at this point if I want to receive. The recvfrom() function doesn't work at this point too. I tried the bind() function instead of connect because in the python script it works with sock.bind. But than I cant send or receive. I was reading several posts about UDP receive function but can't find my mistake. Can someone help me?
The Python code binds to all existing local interfaces at port 5004, whereas the C code will implicitly bind to a local free port during the call to connect(), thus if the remote peer is hard-coded to respond to port 5004, the socket will not receive it.
You should add a call to bind() right after creating your socket:
bind(sock, (sockaddr *)&ADDRESS, sizeof(ADDRESS));
And see what happens :)
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/ip6.h>
#include <netinet/udp.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
struct ip6_hdr;
struct udphdr;
int main(){
int clientSocket, portNum, nBytes;
char buffer[1024];
struct sockaddr_in serverAddr;
struct sockaddr_in6 serverAddr6;
socklen_t addr_size;
struct hostent *hp;
struct msghdr m;
struct in_addr **addr_list;
/*Create UDP socket*/
clientSocket = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
/*Configure settings in address struct*/
hp = gethostbyname2("2001:0db8:0:f101::2", PF_INET6);
memset((char *)&serverAddr6, 0, sizeof(serverAddr6));
memcpy((char *)&serverAddr6.sin6_addr, hp->h_addr, hp->h_length);
serverAddr6.sin6_family = hp->h_addrtype;
// serverAddr6.sin6_port = htons(7891);
serverAddr6.sin6_port = 0;//htons(IPPROTO_RAW);
/*Initialize size variable to be used later on*/
const size_t IPV6_HEADER_LEN = 40;
const size_t UDP_HEADER_LEN = 8;
addr_size = sizeof serverAddr6;
size_t data_len = sizeof(serverAddr6) - IPV6_HEADER_LEN;
/*Populate ip header*/
struct ip6_hdr *iphdr = (struct ip6_hdr *)buffer;
iphdr->ip6_flow = htonl ((6 << 28) | (0 << 20) | 0); // IPv6 version (4 bits), Traffic class (8 bits), Flow label (20 bits)
iphdr->ip6_plen = data_len;
iphdr->ip6_nxt = IPPROTO_UDP;
iphdr->ip6_hops = 64;
//supposing src_addr and dst_addr pointers are never NULL
memcpy(&iphdr->ip6_src, (const in6_addr*)&serverAddr6.sin6_addr, sizeof(in6_addr));
memcpy(&iphdr->ip6_dst, (const in6_addr*)&serverAddr6.sin6_addr, sizeof(in6_addr));
/*Populate UDP header*/
udphdr * udp_header = reinterpret_cast<udphdr *>(buffer + IPV6_HEADER_LEN);
udp_header->source = htons(0);
udp_header->dest = htons(7891);
int len = sizeof(serverAddr6);
uint32_t data_length = (len - (IPV6_HEADER_LEN + UDP_HEADER_LEN));
udp_header->len = htons(data_length + sizeof(udphdr));
udp_header->check = htons(0);
for (int i=0; i<10; ++i)
{
sprintf(buffer, "%d", i);
nBytes = strlen(buffer) + 1;
/*Send message to server*/
if(sendto(clientSocket,buffer,nBytes,0,(struct sockaddr *)&serverAddr6,addr_size) == -1 )
{
printf("sendto(): %s\n", strerror(errno));
exit(0);
}
/*Receive message from server*/
// nBytes = recvfrom(clientSocket,buffer,1024,0,NULL, NULL);
// nBytes = recvmsg(clientSocket,&m,0);
if((nBytes = recvmsg(clientSocket,&m, 0)) == -1)
{
printf("recvmsg(): %s\n", strerror(errno));
// exit(0);
}
printf("Received from server: %s\n",buffer);
}
return 0;
}
I am pretty new to socket programming. I have the following code. It returns
sendto(): Invalid argument
Upon investigation, I have identified that the line containing:
serverAddr6.sin6_port = htons(7891);
*commented out in the code snippet
With the help of Google, I have found a work around solution in
http://osdir.com/ml/linux.ipv6.usagi.users/2003-03/msg00004.html:
From the kernel source code, it seems that when you use raw ipv6 socket, you
have to set
dest.sin6_port = htons(IPPROTO_RAW);
and in http://osdir.com/ml/linux.ipv6.usagi.users/2003-03/msg00005.html:
dest.sin6_port=0;
On the other hand, I cannot go with this proposed solution as I have to specify the port to be something else other than 0.
Any suggestions or explanations?
I am using Python 3, and also encountering OSError: [Errno 22] Invalid argument when sending IPv6 packages. However, when I set the port number of the parameter for sendto to 0, the packets are sent successfully and the port specified in the packet generated by the script (buffer in your program) is still used.
You should use different port numbers for generating the packet and calling sendto. Generate with the desired port number and call with port number 0.
The following is my code
s = socket.socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)
s.setsockopt(IPPROTO_IPV6, IP_HDRINCL, 1)
s.sendto(GenerateIPv6Packet('::1', 53, '::1', 53), ('::1', 0))
# generate the packet with port 53 and call sendto with port 0
Sorry for answering in a different programming language.
I wrote a program that join source specific multicast group and receive udp multicast packets:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <net/if.h>
typedef unsigned int UINT32;
int join_ssm_group(int s, UINT32 group, UINT32 source, UINT32 inter) {
struct ip_mreq_source imr;
imr.imr_multiaddr.s_addr = group;
imr.imr_sourceaddr.s_addr = source;
imr.imr_interface.s_addr = inter;
return setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *) &imr, sizeof(imr));
}
UINT32 LISTEN_INTERFACE = inet_addr("10.10.1.2");
int main(int argc, char *argv[]) {
if (argc<3) {
printf(" Use: %s <group> <source> <port>", argv[0]);
return 1;
}
// Make socket
int sd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
struct sockaddr_in Sender;
socklen_t SenderAddrSize = sizeof( Sender );
struct sockaddr_in binda;
// Bind it to listen appropriate UDP port
binda.sin_family = AF_INET;
binda.sin_port = htons( atoi(argv[3]));
= INADDR_ANY;
// binda.sin_addr.s_addr = LISTEN_INTERFACE;
bind(sd,(struct sockaddr*)&binda, sizeof(binda));
// Join to group
join_ssm_group( sd, inet_addr(argv[1]),
inet_addr(argv[2]),
INADDR_ANY );
char buf[65536];
UINT32 seq;
while(1) {
printf("try receive\n");
int res=recvfrom(sd,(char*)buf,sizeof(buf),0, (struct sockaddr *)& Sender, &SenderAddrSize);
printf("received\n");
seq = *(UINT32*)buf;
printf("scr=:%12s;\tseq=%6d;\tlen=%4d\n", inet_ntoa(Sender.sin_addr), seq, res);
}
return 0;
}
It works fine but note that I'm using binda.sin_addr.s_addr = INADDR_ANY;. netstat shows this:
netstat -a | grep 16002
udp 0 0 0.0.0.0:16002 0.0.0.0:*
When I change it to binda.sin_addr.s_addr = LISTEN_INTERFACE; program stops working - it can not recieve packets, it hangs in recvfrom. netstat shows this:
netstat -a | grep 16002
udp 0 0 localhost.localdo:16002 0.0.0.0:*
In both cases tcpdump shows that data is online, so the problem is that I can not receive data on the specific interface, only on ALL interfaces. I'm using RHEL 7, teaming, and LISTEN_INTERFACE is the IP of the corresponding VLAN. Why my code doesn't work and how to troubleshoot it? I do not want to use INADDR_ANY for performance reasons - listening ALL interfaces would be more expensive than listeining certain interface.
upd passing LISTEN_INTERFACE to both join_ssm_group and and binda.sin_addr.s_addr doesn't work too. BTW similar Windows version of such code works on the same PC under Windows Server 2008 R2, but it doesn't work in RHEL 7. I guess I should check these:
if RHEL 7 receives data on the requreid interface on the required port (answer is Yes, proved by tcpdump)
if socket is listening on the required interface on the required port (answer is Yes, proved by netstat?)
if both answers above are Yes then how is it possible that call to recvfrom doesn't receive data?
Well probably this question more about RHEL 7 now, than about c++.
When you join the multicast group you need to specify the same interface that you are listening on, or join it via all interfaces in a loop.
However listening on all interfaces is the norm. It is not 'slow', and it is a 'good idea', unless you have a specific reason to restrict who can connect.
I have the written the following code for transmitting UDP packets via broadcasting on a wireless network. The application that I have trying to develop requires the packets to be transmitted very fast, but unfortunately I cannot do so and need to add a sleep time. I find that below 500us sleep time, I am unable to send all the packets successfully.
Why does the sleep time have to be so high?
Is it possible to reduce this time by further optimization of this code?
If I do not process the received packets buffer, is it okay? Or does this create problems?
Note that I am running this code on a wireless radio which runs using OpenWrt.
Thanks in advance.
Code:
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <sys/time.h>
#include <arpa/inet.h> /* for sockaddr_in */
#define BROADCAST_IP "192.168.255.255"
#define BROADCAST_PORT 45454
int b_sock=-1;
void init_socket()
{
unsigned short b_port = BROADCAST_PORT;
struct sockaddr_in b_addr;
int broadcastPermission;
char* rx_ip = BROADCAST_IP;
if ((b_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
perror("socket() failed");
/* Set socket to allow broadcast */
broadcastPermission = 1;
if (setsockopt(b_sock, SOL_SOCKET, SO_BROADCAST, (void *) &broadcastPermission, sizeof(broadcastPermission)) < 0)
perror("setsockopt() failed");
int opts;
opts = fcntl(b_sock,F_GETFL);
if(opts < 0)
perror("fcntl get failed");
opts = (opts | O_NONBLOCK);
if(fcntl(b_sock,F_SETFL,opts) < 0)
perror("fcntl set failed");
memset(&b_addr, 0, sizeof(b_addr)); /* Zero out structure */
b_addr.sin_family = AF_INET; /* Internet address family */
b_addr.sin_addr.s_addr = inet_addr(rx_ip);/* Broadcast IP address */
b_addr.sin_port = htons(b_port); /* Broadcast port */
if (bind(b_sock, (struct sockaddr *) &b_addr, sizeof(b_addr)) < 0)
perror("rx bind() failed");
}
void send_thread_body(long int buf, struct sockaddr_in tx_addr)
{
if(sendto(b_sock, &buf, sizeof(long int), 0, (struct sockaddr *)&tx_addr, sizeof(tx_addr)) < 0)
printf("tx sent diff num bytes than expected: %d\n",buf);
}
int main(int argc, char *argv[])
{
init_socket();
{
timeval start, end;
double diff = 0;
long int num = 0;
char *tx_ip = BROADCAST_IP;
unsigned short tx_port = BROADCAST_PORT;
struct sockaddr_in tx_addr;
memset(&tx_addr, 0, sizeof(tx_addr)); /* Zero out structure */
tx_addr.sin_family = AF_INET; /* Internet address family */
tx_addr.sin_addr.s_addr = inet_addr(tx_ip);/* Broadcast IP address */
tx_addr.sin_port = htons(tx_port); /* Broadcast port */
double next = 0;
double st = 0;
while (num<50000)
{
while (st <= next)
{
gettimeofday(&start,NULL);
st = start.tv_sec*1000 + ((double)start.tv_usec)/1000.0;
}
send_thread_body(num,tx_addr);
gettimeofday(&end, NULL);
diff += ((double)(((end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec))))/1000000.0;
num++;
next = end.tv_sec*1000 + ((double)end.tv_usec)/1000.0 + 0.7;
}
printf("Avg time diff: %f\n",diff/50000.0);
}
close(b_sock);
return 0;
}
You are probably overflowing the socket buffer because you set the socket to O_NONBLOCK. Normally (when blocking is enabled), if the socket buffer is full, sendto blocks until there is sufficient buffer space to hold the message for sending.
From http://pubs.opengroup.org/onlinepubs/009695399/functions/sendto.html:
If space is not available at the
sending socket to hold the message to
be transmitted and the socket file
descriptor does not have O_NONBLOCK
set, sendto() shall block until space
is available. If space is not
available at the sending socket to
hold the message to be transmitted and
the socket file descriptor does have
O_NONBLOCK set, sendto() shall fail.
When you added sleeps between your sendto calls, you were effectively throttling down the throughput and preventing the socket buffers from overflowing.
Instead of sleep, you should use a blocking socket. If the socket buffers become full, sendto will block, which is effectively the same thing as sleeping, except that it will automatically stop sleeping the instant the socket is able to hold your next datagram.
To achieve better thoughput, try lumping data into datagrams close to the MTU size (while taking care to save enough room for UDP/IP headers). This should give you smaller header overhead compared to sending very short datagrams.
I have this code, the point is that I want to receive no more than 600Kbits/s using a UDP socket, I implemented an algorithm using duration during which we receive and the sleep command....
#if defined (WIN32)
#include <winsock2.h>
typedef int socklen_t;
#elif defined (linux)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define closesocket(s) close(s)
typedef int SOCKET;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
#endif
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define RCVBUFSIZE 4
#define PORT 4444
#define ECHOMAX 255
int main(void)
{
#if defined (WIN32)
WSADATA WSAData;
int erreur = WSAStartup(MAKEWORD(2,2), &WSAData);
#else
int erreur = 0;
#endif
int recvMsgSize;
char echoBuffer[RCVBUFSIZE];
//unsigned int echoStringLen;
//int bytesRcvd, totalBytesRcvd; //bytes received in a single recv()
SOCKET sock;
SOCKADDR_IN sin;
SOCKADDR_IN SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
if(!erreur)
{
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
sin.sin_family = AF_INET;
sin.sin_port = htons(4444);
memset(&sin.sin_zero, '\0', sizeof(sin.sin_zero));
bind(sock, (SOCKADDR*)&sin, sizeof(sin));
//totalBytesRcvd = 0;
printf("Received: ");
int speed_limit= 614400; //600Kbits/s
int one_second=1000;
int elapsed; //elapsed time
int transmit=0; // how much i receive during 'elapsed'
int expected_receive; //what I'm excpected to receive
int transmit_delta; //diference
int time_sleep; //how much to sleep
clock_t start_time= clock();
for(;;)
{
if((recvMsgSize=recvfrom(sock, echoBuffer,1024, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize)) > 0)
{
transmit+=recvMsgSize;
clock_t tempo= clock();
elapsed=(tempo-start_time)/CLOCKS_PER_SEC;
// Check moment speed every five second, you can choose any value
if(elapsed>5)
{
start_time= tempo;
expected_receive=speed_limit*elapsed/8;
transmit_delta=expected_receive-transmit;
if(transmit_delta>0)
{
time_sleep=8*transmit_delta*one_second/speed_limit;
Sleep(time_sleep);
}
transmit=0;
}
echoBuffer[recvMsgSize]='\0';
printf(echoBuffer);
}
}
printf("\n");
getchar() ;
closesocket(sock);
#if defined (WIN32)
WSACleanup();
#endif
}
return EXIT_SUCCESS;
}
the problem is that it receive the message but it blocks the receiving process from time to time...which I guess will cause loss of data especially when I'm using UDP...
any alternative solution is welcolme...
thanks in advance..
Better not to sleep - just read and discard data while you are over the threshold, then resume processing it once you are ready to do so (after interval expires).
If the data is arriving over UDP, there is no way to reduce the throughput at the receiving end. You'd have to tell the sending computer to send less data. The receiver's only choice is the receive the UDP packets, or let them get dropped, and do something with them, or not.
If you use TCP, then the TCP protocol includes a built-in way to do what you want (called "source quench") ... the TCP protocol layer of the receiver will send a message to the sender telling the sender to slow down if the receiver is having problems keeping up. (and you can influence whether "the receiver is having problems keeping up" by reading the data slower than usual, if you want).
If you use non-blocking sockets with select() you can just ignore the data until you're ready to read it. Not reading data will cause the TCP connection to "slow down". However, this way you do not have exact control about the amount of data received. It's just an approximation. All techniques I know of that limit bandwidth in a more accurate way are implemented on the sender side.