I want to limit access to the device for more than 4 clients on IP address.
struct sockaddr_in peerAddr;
SOCK_LEN_TYPE peerAddrLen = sizeof(peerAddr);
// Yes, socket is free, try to accept a connection on it
connectionSocketArr[sockIdx] = accept(listenSocket, (struct sockaddr *) &peerAddr,
&peerAddrLen);
You can use the sockIdx variable to see how many clients are currently connected.
Instead of storing the socket returned by accept directly in the array, store it in a temporary variable. If sockIdx is larger than 3 then the new client is not allowed to connect, so send a message to the client stating that and close the socket. Otherwise store the socket in the array and increase sockIdx.
Related
I'm looking at the udp client example here:
http://www.linuxhowtos.org/data/6/client_udp.c
snippet:
/* UDP client in the internet domain */
struct sockaddr_in server, from;
//...snipped
sock= socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) error("socket");
server.sin_family = AF_INET;
hp = gethostbyname(argv[1]);
if (hp==0) error("Unknown host");
bcopy((char *)hp->h_addr,
(char *)&server.sin_addr,
hp->h_length);
server.sin_port = htons(atoi(argv[2]));
length=sizeof(struct sockaddr_in);
//... snipped
n=sendto(sock,buffer,
strlen(buffer),0,(const struct sockaddr *)&server,length);
if (n < 0) error("Sendto");
n = recvfrom(sock,buffer,256,0,(struct sockaddr *)&from, &length);
if (n < 0) error("recvfrom");
//... snipped
I'm trying to understand how it knows where to receive the message from. I know when sendto is called an available port is chosen and that is embedded in the udp message and the server application can read that and reply to it. How does the client code know to receive a message on that port?
This answer: https://stackoverflow.com/a/48245273/2748602 indicates there is kind of an implicit bind when the sendto function is called. How does it work? Is it in fact a bind with a random available port number that is as permanent as if I had called bind or something else? It seems there's some aspect of permanence. Just interested in a little more detail.
There is an implicit bind if the socket is unbound since all packets have to carry both a source port. So the API assumes that if you didn't care enough about the port to bind your socket beforehand, then it can just bind the socket to a random port. And while unfortunately I don't know the implementation details of sendto, I can offer some official documentation.
For Linux, from the udp man page:
When a UDP socket is created, its local and remote addresses are
unspecified. Datagrams can be sent immediately using sendto(2) or
sendmsg(2) with a valid destination address as an argument. When
connect(2) is called on the socket, the default destination
address is set and datagrams can now be sent using send(2) or write(2)
without specifying a destination address. It is still possible to
send to other destinations by passing an address to sendto(2) or
sendmsg(2). In order to receive packets, the socket can be bound to a
local address first by using bind(2). *Otherwise, the socket layer
will automatically assign a free local port out of the range defined
by /proc/sys/net/ipv4/ip_local_port_range and bind the socket to
INADDR_ANY.
For Windows, a snippet from the documentation for Winsock 2's sendto:
If the socket is unbound, unique values are assigned to the local
association by the system, and the socket is then marked as bound. If
the socket is connected, the getsockname function can be used to
determine the local IP address and port associated with the socket.
... there is kind of an implicit bind when the sendto function is called. How does it work? Is it in fact a bind with a random available port number that is as permanent as if I had called bind or something else?
man ip(7):
ip_local_port_range (since Linux 2.2)
This file contains two integers that define the default local
port range allocated to sockets that are not explicitly bound
to a port number—that is, the range used for ephemeral ports.
An ephemeral port is allocated to a socket in the following
circumstances:
* the port number in a socket address is specified as 0 when calling bind(2);
* listen(2) is called on a stream socket that was not previously bound;
* connect(2) was called on a socket that was not previously bound;
* sendto(2) is called on a datagram socket that was not previously bound.
I'm in the process of writing a project for college involving writing a chat client and server using POSIX sockets and C++.
The clients are supposed to converse with each other using P2P, such as each client has his own open UDP socket through which he sends and recieves messages from/to other clients.
My problem is 2-fold:
My UDPSocket class constructor seems to be ignoring the port number completely, binding to port 65535 regardless of the parameter.
The port is binding to IP 255.255.255.255 rather than my own IP (10.0.0.3), or at least that's what i get when I call getpeername.
To the best of my knowledge passing INADDR_ANY should bind to my local address, and passing port number 0 should make the OS choose a free port, what am I doing wrong?
This is the constructor of my UDPSocket class:
UDPSocket::UDPSocket(int port){
socket_fd = socket (AF_INET, SOCK_DGRAM, 0);
// clear the s_in struct
bzero((char *) &in, sizeof(in)); /* They say you must do this */
//sets the sin address
in.sin_family = (short)AF_INET;
in.sin_addr.s_addr = htonl(INADDR_ANY); /* WILDCARD */
in.sin_port = htons((u_short)port);
fsize = sizeof(from);
//bind the socket on the specified address
if(bind(socket_fd, (struct sockaddr *)&in, sizeof(in))<0){
perror ("Error naming channel");
}
}
This is the initialization:
m_Socket = new UDPSocket(0);
And this is the method I use to retrieve the binded address: (UDPSocket inherits Socket)
std::string Socket::GetSocketAddress()
{
struct sockaddr_in addr;
int len = sizeof(addr);
getpeername(socket_fd, (struct sockaddr*)&addr, (socklen_t*)&len);
char ipAddressBuffer[50];
memset(ipAddressBuffer, 0, sizeof(ipAddressBuffer));
sprintf(ipAddressBuffer, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
return ipAddressBuffer;
}
Any help would be greatly appreciated,
Avi.
You're using getpeername , which gives you the remote address of a connected socket. If you check the return value of getpeername(), it should indicate failure.
You need to use getsockname() instead of getpeername() to get the address of your local socket
You need to check that getsockname() succeeds.
Note that your socket is bound to the special 0.0.0.0 address, which means "all local interfaces", so that's what getsockname() will also return.
Answering the more general question "How to set up peer-to-peer communications with UDP":
With UDP sockets, while you can use connect, you generally don't want to, as that restricts you to a single peer per socket. Instead, you want to use a single unconnected UDP socket in each peer with the sendto and recvfrom system calls to send and receive packets with a different address for each packet.
The sendto function takes a packet and a peer address to send it to, while the recvfrom function returns a packet and the peer address it came from. With a single socket, there's no need to multiplexing with select or poll -- you just call recvfrom to get the next packet from any source. When you get a packet, you also get the peer address to send packets (back) to.
On startup, your peer will create a single socket and bind it to INADDR_ANY (allowing it to receive packets on any interface or broadcast address on the machine) and either the specific port assigned to you program or port 0 (allowing the OS to pick any unused port). In the latter case, you'll need to use getsockname to get the port and report it to the user. Once the socket is set up, the peer program can sendto any peer it knows about, or recvfrom any peer at all (including those it does not yet know about).
So the only tricky part is bootstrapping -- getting the first packet(s) flowing so that peers can recieve them and figure out their peer addresses to talk to. One method is specifying peer addresses on the command line when you start each peer. You'll start the first one with no arguments (as it has no peers -- yet). It will just recvfrom (after socket setup) to get packets from peers. Start the second with the address of the first as an argument. It sends a packet (or several) to the first peer, which will then know about the new peer as soon as it gets the first packet. Now start a third client with the addresses of the first two on the command line...
I want to connect 2 clients to same server port using TCP IP. I have use the below code before bind:-
// Reuse already binded socket
int reuse=1;
setsockopt(m_iSocketId, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse))
listen(iSocketId, 2);
struct sockaddr clientAddr;
socklen_t length = sizeof(clientAddr);
int firstClientSocket = accept(iSocketId, &clientAddr, &length);
length = sizeof(clientAddr);
int secondClientSocket = accept(iSocketId, &clientAddr, &length);
After this code, you will have two client sockets to work with. Note, however that 'accept' function blocks until some client connects. In general, you should use some aync methods (e.g. select) to handle multiple clients.
SO_REUSEADDR is generally not intended for your purposes. It just tells the system that the listening port can be reused by multiple instances of the server. It's good for debugging, when your app doesn't close the socket properly upon exit. Otherwise the system might hold the port for some time, refusing to bind another socket to it.
And don't forget error handling on listen and accept calls =)
You don't need to set SO_REUSEADDR for this. You don't need to do anything special. Just create and connect as many sockets in the client as you need, and keep calling accept() in the server.
Suppose I have a simple winsock server that has a listening socket, and then when a connection is accepted, it stores the socket in an array of sockets (to allow multiple connections).
How can I get the IP address of a specific connection? Is it stored in the socket handle?
As long, as the socket stays connected, you can get both own socket address and peer one.
getsockname will give you local name (i.e. from your side of a pipe)
getpeername will give you peer name (i.e. distant side of a pipe)
This information is available only when the socket is opened/connected, so it is good to to store it somewhere if it can be used after peer disconnects.
Yes it is stored in the socketaddr_in struct, you can extract it using:
SOCKADDR_IN client_info = {0};
int addrsize = sizeof(client_info);
// get it during the accept call
SOCKET client_sock = accept(serv, (struct sockaddr*)&client_info, &addrsize);
// or get it from the socket itself at any time
getpeername(client_sock, &client_info, sizeof(client_info));
char *ip = inet_ntoa(client_info.sin_addr);
printf("%s", ip);
I cant seem to figure out how to do the next step for my UDP server. So far one client connects and then it sends data back and forth but when another client connects the server will take data from the new client and send it to the other.
I was going to check if the message that has been received is from a new client or not, if it is then give that client an identifier that the server uses to do some processing. Is that the correct way to do it? If so how do you do it? I know that recvfrom has "sockaddr *from" field which I assume fills that field with the data of the client but how do I use that data?
Thanks
sockaddr_in saddr;
int length = sizeof(saddr);
int read = recvfrom(your_socket, buff, 4096, 0, (sockaddr*)&saddr, &length);
if(read != -1) {
// now saddr contains the address of the client
// the g_addr is a previously captured client address
if(saddr.sin_addr.S_un.S_addr = g_addr.sin_addr.S_un.S_addr) {
// returning client?
} else {
// not yet seen client, so store address
}
}
UDP is connection-less. Try using TCP. Why did you decide to use UDP? What are your constraints?
The address in the recvfrom function will be filled with the source information from the client. In the case if udp it will give you address and port, which for IPv4 can easily be converted to a long long and stored as an identifier. IPv4 is 4 bytes + port 2 bytes. You will need to cast the pointer to sockaddr_in and then get the values of sin_port and sin_addr.