How to receive message from only desired client if I know that this client has been connected to my server?
recvfrom(sockfd, buf, BUFFSIZE, MSG_PEEK,
(struct sockaddr *)&addr, &caddrlen);
addr will be replaced by corresponding data, but I want receive data from only one client
How to receive message from only desired client if I know that this client has been connected to my server?
You can't really do this with a datagram socket in the AF_INET or AF_INET6 family, unless undesired clients are blocked at a lower level, such as via a firewall. At least, not if you want to be able to continue to receive messages from desired clients after one from an undesired client arrives. The network driver queues datagrams for you, and you need to handle them in order, where the C API for "handling" a datagram is to receive it via one of the several system calls that serve that purpose, such as recvfrom().
You can discriminate between messages after receiving them, such as by discarding those from undesired clients. However, it is of limited, special-purpose use to retrieve message data without dequeueing it, as the MSG_PEEK flag to recvfrom() provides. In particular, that does not serve your stated purpose -- you will still need to receive every message, via a subsequent call that does not use MSG_PEEK. Instead, I suggest simply reading the data via recvfrom(), checking the address to determine whether it's from the client you're interested in, and handling it appropriately.
If you want to handle multiple clients at the same time, then you have some alternatives. A relatively simple one is to have a function, perhaps running in a dedicated thread, that receives all incoming messages and dispatches them appropriately according to their source addresses. Another alternative is to open a new (datagram) socket for each client, each on its own port, and to set up a protocol by which you tell each client which port to use after their first contact. Datagrams from unexpected clients on these additional ports would be erroneous, and therefore safe to reject.
Of course, the latter of those is an approximation to a connection-oriented protocol. If it seems attractive to you then perhaps you should be looking at stream sockets instead of datagram sockets. Not only would that get you no-fuss client specificity, it would also provide for reliable and guaranteed in-order communication.
recvfrom(sockfd, buf, BUFFSIZE, MSG_PEEK,
(struct sockaddr *)&addr, &caddrlen);
if(addr.sin_addr.s_addr == "ADDRESS_OF_DESIRED_CLIENT")
{
//ALLOW USER
}
For IPV4 "addr.sin_addr.s_addr" is an int, but you can also get the Address in a string from.
Related
In C, to receive/send data you usually do(roughly):
Server:
Create socket
Bind socket to port
listen
Accept
Receive Send data
On client side:
Create socket
Connect
Receive send
My question comes after server has done accept.
Imagine after accept on the server side there are three separate lines
to send data:
connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL);
write(connfd, var1, var1Size);
write(connfd, var2, var2Size);
write(connfd, var3, var3Size);
Does this mean on the client side I need to have three reads?
Like this:
read(sockfd, &x, size1);
read(sockfd, &y, size2);
read(sockfd, &z, size3);
In other words how should send and receive calls correspond
on server and client side? Should for each send be a corresponding receive on the client side?
What if on client side, after 3 read calls(like above), I want to send data to server?
Shall I just add one new send and one new receive on client and server side respectively?
Should all these send/receives be happening within a single accept call context?
Here is a image to better illustrate what kind of scenario I could be interested in:
Pseudo code explaining how to handle this kind of connections would be welcome.
Unless you are working with a protocol which has a concept of "messages", e.g. UDP, all you have is a stream of bytes. You can send and receive them any way you wish.
You could, for example, send two 16-bit integers and receive them as one 32-bit integer. This is probably not what you intended but it's perfectly legal and used all the time in situations where it is needed. You can compose data structures on either side (sending and receiving) independandly, as long as it makes sense to your application.
Your bytes are sent in the order of your write()'s and you WILL receive them in the same order. I.e.
send(var1) ---> recv(var1)
send(var2) ---> recv(var2)
There is no way in normal TCP (barring unused edge cases which I'll not even specify because nobody should use them) that you will receive var2 before var1.
TCP communication is bi-directional: each end-point (client and server) can send at the same time. It is up to you and your application to decide when to send and when to receive. The sending and receiving buffers are independant: you can send a few bytes, receive a few, send some more... and there will be no interference between them (i.e. you will not "overwrite" the receive buffer by sending some data nor vice versa).
I'll repeat it again: ALL you have in TCP is a stream of bytes. TCP doesn't know and doesn't care how these bytes are structured, neither on the sending nor on the receiving side. It's ALL up to you. When you send an integer or a data structure, you are sending a memory dump of those, as bytes.
For example, there's a common error where you attempt to send() a data structure and because the sending buffers are full, the system will make a partial write. If you do not check the return status of the send() call to detect this situation and then send the remainder of bytes by yourself, in another send() call, your client WILL be stuck in recv() when it expects the full structure and receives only a part of it, if you specify MSG_WAITALL.
TCP is a stream protocol, In the receiver side you cannot determine how many times the send has been called. Whenever recv is called it will give the number of bytes asked to read, if the requested number of bytes are not available then it will return the number of bytes currently in the socket buffer.
In case of UDP it will work as you mentioned, It is a datagram protocol. (use recvfrom to recv the data)
I want to make a multi client - one server quiz application. In this, firstly, the clients will connect to the server and will registered themselves. Then, the server will multicast a question to every client, who have registered themselves to the server. The clients will then respond with the answer, which will be send only to the server. And then server will send the the score of each client to the respective client.
This is what I am trying to do in the above application-
1. As I have too multicast, thats why I am Making my server socket asSOCK_DGRAM (i.e.,UDP). Then I am using CLASS-D ip address, for making a group( to which server will multicast). Then is using setsockopt, I am adding the clients to this group, so that they can recieve the question.
2.As I want to listen the answers from all the clients, so I was thinking of using select. It uses the socket descriptor to select between various clients, as to know which is ready for reading.
But the problem is, when I am using SOCK_DGRAM socket, it doesnot perform listen and accept functionality. So, I will not get a socket descriptor(which is returned by accept). Thats why, I will not be able to use select(as it uses only file descriptors).
So, how am I to proceed, as I want to use UDP functionality - MULTICASTING, as well as TCP functionality - a socket descriptor for each connection.
Even when using UDP and unconnected sockets, you can still use functions like select. Simply bind the server socket to an address, and use that socket for select. When the socket is readable a client has sent something with e.g. sendto and you can do e.g. recvfrom.
However, I would really recommend you to use TCP sockets, it will make many things simpler, especially when it comes to the communication protocol (remember that UDP packages can be lost or come out of order, you have to handle that yourself).
As you said, select is not usefull here since you only have one socket on the server side.
This socket is used to send datagrams with sendto
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
in dest_addr you specify the destination address for the datagram.
Using recvfrom(2) on a UDP socket is similar :
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
src_addr is the sender address, so you are able to identify the client which has sent the response.
recvfrom calls are blocking until data are available for reading (unless you set the socket to unblocking).
You could just loop to receive all the responses.
You're on the right track but you don't need listen() or accept(). Just select for readability. When the socket becomes readable, read it. You probably don't need select() for this at all, really, just a blocking read, with a timeout if you like.
I am working on a LAN based solution with a "server" that has to control a number of "players"
My protocol of choice is UDP because its easy, I do not need connections, my traffic consists only of short commands from time to time and I want to use a mix of broadcast messages for syncing and single target messages for player individual commands.
Multicast TCP would be an alternative, but its more complicated, not exactly suited for the task and often not well supported by hardware.
Unfortunately I am running into a strange problem:
The first datagram which is sent to a specific ip using "sendto" is lost.
Any datagram sent short time afterwards to the same ip is received.
But if i wait some time (a few minutes) the first "sendto" is lost again.
Broadcast datagrams always work.
Local sends (to the same computer) always work.
I presume the operating system or the router/switch has some translation table from IP to MAC addresses which gets forgotten when not being used for some minutes and that unfortunately causes datagrams to be lost.
I could observe that behaviour with different router/switch hardware, so my suspect is the windows networking layer.
I know that UDP is by definition "unreliable" but I cannot believe that this goes so far that even if the physical connection is working and everything is well defined packets can get lost. Then it would be literally worthless.
Technically I am opening an UDP Socket,
bind it to a port and INADRR_ANY.
Then I am using "sendto" and "recvfrom".
I never do a connect - I dont want to because I have several players. As far as I know UDP should work without connect.
My current workaround is that I regularly send dummy datagrams to all specific player ips - that solves the problem but its somehow "unsatisfying"
Question: Does anybody know that problem? Where does it come from? How can I solve it?
Edit:
I boiled it down to the following test program:
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET Sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
SOCKADDR_IN Local = {0};
Local.sin_family = AF_INET;
Local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
Local.sin_port = htons(1234);
bind(Sock, (SOCKADDR*)&Local, sizeof(Local));
printf("Press any key to send...\n");
int Ret, i = 0;
char Buf[4096];
SOCKADDR_IN Remote = {0};
Remote.sin_family = AF_INET;
Remote.sin_addr.S_un.S_addr = inet_addr("192.168.1.12"); // Replace this with a valid LAN IP which is not the hosts one
Remote.sin_port = htons(1235);
while(true) {
_getch();
sprintf(Buf, "ping %d", ++i);
printf("Multiple sending \"%s\"\n", Buf);
// Ret = connect(Sock, (SOCKADDR*)&Remote, sizeof(Remote));
// if (Ret == SOCKET_ERROR) printf("Connect Error!\n", Buf);
Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote));
if (Ret != strlen(Buf)) printf("Send Error!\n", Buf);
}
return 0;
The Program opens an UDP Socket, and sends 3 datagrams in a row on every keystroke to a specific IP.
Run that whith wireshark observing your UDP traffic, press a key, wait a while and press a key again.
You do not need a receiver on the remote IP, makes no difference, except you wont get the black marked "not reachable" packets.
This is what you get:
As you can see the first sending initiated a ARP search for the IP. While that search was pending the first 2 of the 3 successive sends were lost.
The second keystroke (after the IP search was complete) properly sent 3 messages.
You may now repeat sending messages and it will work until you wait (about a minute until the adress translation gets lost again) then you will see dropouts again.
That means: There is no send buffer when sending UDP messages and there are ARP requests pending! All messages get lost except the last one.
Also "sendto" does not block until it successfully delivered, and there is no error return!
Well, that surprises me and makes me a little bit sad, because it means that I have to live with my current workaround or implement an ACK system that only sends one message at a time and then waits for reply - which would not be easy any more and imply many difficulties.
I'm posting this long after it's been answered by others, but it's directly related.
Winsock drops UDP packets if there's no ARP entry for the destination address (or the gateway for the destination).
Thus it's quite likely some of the first UDP packet gets dropped as at that time there's no ARP entry - and unlike most other operating systems, winsock only queues 1 packet while the the ARP request completes.
This is documented here:
ARP queues only one outbound IP datagram for a specified destination
address while that IP address is being resolved to a MAC address. If a
UDP-based application sends multiple IP datagrams to a single
destination address without any pauses between them, some of the
datagrams may be dropped if there is no ARP cache entry already
present. An application can compensate for this by calling the
Iphlpapi.dll routine SendArp() to establish an ARP cache entry, before
sending the stream of packets.
The same behavior can be observed on Mac OS X and FreeBSD:
When an interface requests a mapping for an address not
in the cache, ARP queues the message which requires the
mapping and broadcasts a message on the associated associated
network requesting the address mapping. If a response is
provided, the new mapping is cached and any pending message is
transmitted. ARP will queue at most one packet while waiting
for a response to a mapping request; only the most recently
``transmitted'' packet is kept.
UDP packets are supposed to be buffered on receipt, but a UDP packet (or the ethernet frame holding it) can be dropped at several points on a given machine:
network card does not have enough space to accept it,
OS network stack does not have enough buffer memory to copy it to,
firewall/packet filtering drop-rule match,
no application is listening on destination IP and port,
receive buffer of the listening application socket is full.
First two points are about too much traffic, which is not likely the case here. Then I trust that point 4. is not applicable and your software is waiting for the data. Point 5. is about your application not processing network data fast enough - also does not seem like the case.
Translation between MAC and IP addresses is done via Address Resolution Protocol. This does not cause packet drop if your network is properly configured.
I would disable Windows firewall and any anti-virus/deep packet inspection software and check what's on the wire with wireshark. This will most likely point you into right direction - if you can sniff those first packets on the "sent-to" machines then check local configuration (firewall, etc.); if you don't, then check your network - something in the path is interfering with your traffic.
Hope this helps.
erm ..... Its your computer doing ARP request. When you first start sending, your com does not know the receiver mac address, hence its unable to send any packets. It uses the ip address of the receiver to do an ARP request to get the mac address. During this process, any udp packets you try to send cannot be send out as the destination mac address is still not known.
Once your com receive the mac address it can start sending. However, the mac address will only remain in you com's ARP cache for 2mins (if no further activities is detected between you and the receiver) or 10 mins (full clear of ARP cache, even if connection is active). That is why you experience this problem every few mins.
Does anybody know that problem?
The real problem is that you assumed that UDP packet sending is reliable. It isn't.
The fact that you lose the first packet with your current network configuration is really a secondary issue. You might be able to fix that, but at any point you are still vulnerable to packet losses.
If packet loss is a problem for you, then you really should use TCP. You can build a reliable protocol on UDP, but unless you have a very good reason to do so, it's no recommended.
I have the following issue here: I want to write a server streaming data on a UDP socket on a specific port, and clients should be able to connect to it and receive the data that is being sent out without too much hassle: they just connect, and from the moment they start they should get data using recvfrom from the server.
I have some problems with setting up the network related parts. So, here is a rough piece of code that I try to make work:
int udpSock = socket(AF_INET, SOCK_DGRAM, 0);
if(udpSock == -1)
{
perror("Could not create audio output socket");
exit(1);
}
struct sockaddr_in *sin = (struct sockaddr_in*)&gOutgoingAddr;
sin->sin_port = htons(40200);
if(bind(udpSock, (const sockaddr*)sin, sizeof(struct sockaddr_in)) == -1)
{
perror("Cannot bind audio socket");
exit(1);
}
int buffer_size = 0;
char* data = get_next_buffer(&buffer_size);
while(buffer_size > 0)
{
if(sendto(udpSock, (const void*)(data), buffer_size, 0, NULL, 0) == -1)
{
perror("sendto failure");
}
data = get_next_buffer(&buffer_size);
}
Do not worry about the gOutgoingAddr variable, it is obtained correctly using getifaddrs, it is valid. I am troubled regarding the parametrization of the sendto method, becasue right now the output of the application is:
sendto failure: Destination address required
That's true, because I don't have a destination address, since all the examples I have found till now show when the server gets a client connection, and there is the address. But since I don't have a client yet connected, I'd still want to stream out.
I appreciate all help, I have no idea what Ishould put for the parameters of sendto:
The gOutgoingAddress which is the address where I create the socket? I have tried this, but if I use the tcpdump linux command on the specified port, I get nothing.
Should I create a multicast socket? This somehow makes no sense...
Something else?
Thanks,
frc
You cannot stream out to "nowhere". Streaming data via UDP is not multicast. That means if you have 100 clients connected, you must send exactly the same data 100-times, once to each of the clients that shall receive it. Multicast was not really part of the initial IPv4 design. It has been added later on and is not widely supported. This is contrary to IPv6, where multicast has been part of the initial design. The only thing you could do it broadcast the traffic within your local network. This will only work if all clients are in your local network segment. To broadcast your server would simply send the data to 255.255.255.255 and to a fixed UDP port. All clients then have to listen on that specific port and will receive the data. Please note, that on most systems you need special permissions for broadcasting (e.g. it is not common that only programs running with root privileges are allowed to broadcast traffic, as broadcasts pollute your network, since all broadcast packets are sent to all clients in the network, whether they care for them or not). Without broadcasts, you have only unicast and unicast means one sender, one receiver. For one sender multiple receiver, you must send out the same data multiple times to multiple addresses.
What is audioUdpSock by the way?
Shoudn't you be using udpSock instead?
Do a recvfrom in your server, and have the client send a message (with whatever content you want, this is just a way to establish the connection, a greeting). Then the server will have the client address from the recvfrom, and can send packet to it.
As UDP socket are connection-less (there is no need for accept and connect when using UDP socket), you need to have another way to inform the server of the existence of the client (and the client need to have an out-of-bound way to know the server address, generally, the user give it, or it is hard-coded).
If you can have multiple clients, then you'll have to use select, poll, ... on the socket to know when it is safe to call recvfrom without blocking (or you could configure your socket to be non-blocking).
Edit: I highly recommend Beej's Guide to Network Programming to everyone, and for your question, you can directly go to the sample usage of Datagram Socket.
So I've created a DNS proxy in C. I'm using DIG as the client program; it sends a query packet to my server, my server forwards it to a DNS, and my server receives the answers, then sends them back to the client.
My server is bound to a UDP socket; I'm transmitting the DNS packet via TCP. However, my recv() call (from the TCP socket) is always returning 0. I'll get the original query back, but without answers.
Code:
fromlen=sizeof(client);
recvfrom(UDPSock,buffer,sizeof(buffer),0,(struct sockaddr *)&client,&fromlen); //receive from client
int msglen=strlen(buffer);
connect(TCPSock,(struct sockaddr*) &dest, sizeof(dest)); //connect to DNS
int m=send(TCPSock,buffer,msglen,0); //send packet to dns
recv(TCPSock,buffer,sizeof(buffer),0); //this returns 0
//send back
sendto(UDPSock,buffer,sizeof(buffer),0,(struct sockaddr *)&client,fromlen); //send message back`
The buffer is 300 bytes.
Your immediate problem is that you're not speaking the correct protocol. The DNS/TCP/IP protocol is not identical to the DNS/UDP/IP protocol. Read the RFCs describing the protocols and follow them.
Your more fundamental problem is a design problem with your code as given. It doesn't really make sense, not least in terms of network overhead, to have one-connection-per-query TCP/IP on the back end when there's only UDP/IP on the front end. Moreover: A properly written forwarding proxy DNS server has to cope with large UDP/IP packets, truncated responses, truncated and otherwise malformed queries, TCP/IP connection timeouts and resets, loop detection, and DNS/UDP/IP retry. But this is beyond the scope of the question.
Aside from not checking for errors from any of the system calls one big problem is the strlen(3) use. The recvfrom(2) tells you how many bytes it placed in your buffer (or -1 for error). Some of these bytes could have zero values so the strlen(2) is not at all applicable in this case. Fix that and see if it helps. Otherwise you'd have to explain why you forward over TCP and connect on every packet.
recv() returns zero when the other end disconnects. So you are making the other end disconnect rather than send any data. Probably it doesn't understand what you are sending.