I have the following typical code in C under Linux to get UDP data:
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
mysock.sin_family = AF_INET;
mysock.sin_addr.s_addr = INADDR_ANY;
mysock.sin_port = my_port;
bind(sock, &mysock, sizeof(mysock);
recvfrom(sock, buf, PKTSZ, 0, &client, len);
All the above code works, but now I have a need to find out the sender's udp port, is there a structure or system call I can use to retrieve such info when I receive a udp packet ?
thanks
recvfrom(sock, buf, PKTSZ, 0, &client, len);
The senders socket address is stored in the client variable of your code. To access the senders port use sockaddr_in instead of sockaddr. Example:
sockaddr_in client;
int len = sizeof(client);
recvfrom(sock, buf, PKTSZ, 0, (struct sockaddr *)&client, (socklen_t *)&len);
int port = ntohs(client.sin_port);
References:
Beej's Guide to Network Programming and MSDN
recvfrom() is supposed to return that to you in the fifth argument (struct sockaddr*).
EDIT:
Use something like this
struct sockaddr_in client;
recvfrom(... (struct sockaddr*)&client ...);
client.sin_port should be the sender's port.
UDP sender port would be transient. I don't think you could use that for anything other than for reporting.
The fifth argument can be cast to struct sockaddr_in, and there sin_port is the remote port number.
Casting the client to sockaddr_in solves my problem.
Yes! Remember the ntohs() above all! It wasn't until I used the programmer's calculator that I realized it WAS stored as BigEndian 15B3, not the presumably ephemeral port B315!
Related
I'm trying to reuse connected socket fd.
I've created connfd and connected it to the server in initialisation code.
And in some other function, I do not reconnect it again, but try connfd directly..
On server,
connfd = accept(listenfd, (struct sockaddr *)&cliAddr, &len);
recvfrom(connfd, msg, TCP_DATA_LEN, 0, (struct sockaddr *)&cliAddr, &len);
On client,
sendto(sockfd, messageString, strlen(messageString), 0, (struct sockaddr *)&servAddr, sizeof(servAddr));
sockfd is from
socket(AF_INET, SOCK_STREAM, 0);
connect(sockfd, (struct sockaddr *)&servAddr, sizeof(servAddr));
But on the server, I do not receive anything.
did the code for each apply 'connect()' to their respective sockets?
the server needs to first accept() then listen() where listen() will return a new socket.
That new socket is what is used to recv() from the client.
recvfrom() and sendto() are for datagram (UDP) sockets not SOCK_STREAM (TCP) sockets.
so the code should use send() and recv().
suggest reading the man pages for the system functions the code uses
here is a link to an example, Note the example spawns a thread to handle the connection. for a single connection, the thread is not necessary.
http://www.mycplus.com/source-code/c-source-code/tcp-client-and-server/
sendto and recvfrom are for use with non-connection oriented sockets (SOCK_DGRAM rather than SOCK_STREAM), and may fail with EISCONN if you use them on connected sockets. Even if they work, the extra arguments are meaningless, so there's never any reason to use them on a connected socket.
Just use send and recv on connected sockets.
On linux I want to connect to a demon, via a socket in a compiled c.cgi program (cgic), which is listening for incoming socket connections. I know the server works because it will responded to 'nc' commands. Assume the server is black-boxed, I can't change it. In my client program I have:
int sockfd;
int len;
struct sockaddr_in address;
int result;
char ch[] = "get=DeviceNo";
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = 3042;
len = sizeof(address);
result = connect(sockfd, (struct sockaddr *) &address, len);
Which returns with a "Connection Refused" error at this point. As a test I compiled the netcat into the .cgi program which does work:
system("echo '-r get=DeviceNo' | nc localhost 3042");
Am I missing something maybe how the socket class is handled within a .cgi? What should I do to try and get this socket to connect or what can I do to further troubleshoot my problem?
When working with sockaddr_in type, you need to know that both socket address sin_addr.s_addr and port sin_port must be in network byte order. Most likely your host is little-endian.
So you need to use inet_addr returns correct value, but for the socket address you need to use:
address.sin_port = htons(3042);
self._socket = socket(AF_INET, SOCK_DGRAM, 0);
// create addr
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(0);
addr.sin_addr.s_addr = INADDR_ANY;
// bind socket
bind(self._socket, (struct sockaddr *)&addr, sizeof(addr));
printf("befor getsockname()->%d\n", ntohs(addr.sin_port));
socklen_t len = sizeof(addr);
getsockname(self._socket, (struct sockaddr *)&addr, &len); // if i comment this func, the last printf() will print 0; if not, it will print a real in use udp port(and it is correct!)
printf("after getsockname()->%d\n", ntohs(addr.sin_port));
So, is that when assign htons(0) to a port, the local socket must use getsockname() to assign a available port to itself? Or anything else?
I think this is maybe because i just bind 0 to sin_port which mean to assign a random port but has not assigned by system yet, so just call getsockname() to make system really assign a port.
So, is that when assign htons(0) to a port, the local socket must use getsockname() to assign a available port to itself? Or anything else?
No, you must use bind() to assign a port to the socket. getsockname() tells you what port was assigned if you specified zero.
The whole point of the getsockname function is to get the sockaddr for the local side of the socket. For IPv4 sockets, this is an object of type sockaddr_in and it contains both the IP address and port.
I want to get the IP address of the client who’s just connected into my server running WinSock2. I’m using C.
You could get the client's IP-address and port via the call to accept().
Just pass in the appropriate data into the last two parameters.
struct sockaddr_in sa = {0}; /* for TCP/IP */
socklen_t socklen = sizeof sa;
... = accept(..., (struct sockaddr *) &sa, &socklen);
For details please read here.
Have not done it myself, but take a look at getpeername. Looks like this is what you need.
This work for me on winsock2. No need of getpeername
SOCKET newConnection;
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen);
char *ip = inet_ntoa(addr.sin_addr);
printf("Accepted Connection from : %s", ip);
I have a C code snippet that listens on UDP socket for incomming messages (and it works fine):
uint32_t udp_port = 101010; // example port
int sock_udp = socket(AF_INET, SOCK_DGRAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(udp_port);
bind(sock_udp, (struct sockaddr*) &server_address, (socklen_t) sizeof(server_address));
char buffer[20];
struct sockaddr_in sender_address;
socklen_t sender_len = (socklen_t) sizeof(struct sockaddr_in);
ssize_t rcv_len = recvfrom(sock_udp, buffer, sizeof(buffer), 0, (struct sockaddr * ) &sender_address, &sender_len);
After it I have information on the sender in sender_address structure and I can check addres, port etc. My question is: can I use recv, recvfrom or other similar function to listen for datagrams coming from a certain host? In other words, is it possible to drop datagrams from other sources without reading them?
You can "filter" and receive datagrams from a specified single source if you connect(2) the datagram socket.
If the socket sockfd is of type SOCK_DGRAM then addr is the address to
which datagrams are sent by default, and the only address from which
datagrams are received.
The standard phrases it a little different:
For SOCK_DGRAM sockets, the peer address identifies where all
datagrams are sent on subsequent send() functions, and limits the
remote sender for subsequent recv() functions