I have a Linux C application that must use UDP. The server broadcasts a "discovery packet" and then listens for any connected clients to answer with a similar echo. By using ports, the clients and server can then communicate using their different ports.
Here is how the server broadcasts its discovery packet:
int main() {
puts("starting");
int sock;
int yes = 1;
struct sockaddr_in broadcast_addr;
int addr_len;
int count;
int ret;
fd_set readfd;
char buffer[1024];
char outbound_buffer[63];
int i;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("sock error");
return -1;
}
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes));
if (ret == -1) {
perror("setsockopt error");
return 0;
}
memset(outbound_buffer,0,sizeof(outbound_buffer));
addr_len = sizeof(struct sockaddr_in);
memset((void*)&broadcast_addr, 0, addr_len);
broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
broadcast_addr.sin_port = htons(PORT);
outbound_buffer[0] = 0xEF;
outbound_buffer[1] = 0xFE;
outbound_buffer[2] = 0x02;
ret = sendto(sock, outbound_buffer, 63, 0, (struct sockaddr*) &broadcast_addr, addr_len);
This works fine; the client receives the discovery and gets the server's IP and port:
int main() {
stoplink = 0;
stopData = 0;
int addr_len;
int count;
int ret;
fd_set readfd;
char buffer[1024];
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("sock error\n");
return -1;
}
addr_len = sizeof(struct sockaddr_in);
memset((void*)&server_addr, 0, addr_len);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(PORT);
ret = bind(sock, (struct sockaddr*)&server_addr, addr_len);
if (ret < 0) {
perror("bind error\n");
return -1;
}
while (1) {
puts("Initialized; await discovery");
FD_ZERO(&readfd);
FD_SET(sock, &readfd);
ret = select(sock+1, &readfd, NULL, NULL, 0);
if (ret > 0) {
if (FD_ISSET(sock, &readfd)) {
count = recvfrom(sock, buffer, 1024, 0, (struct sockaddr*)&client_addr, &addr_len);
if((buffer[0] & 0xFF) == 0xEF && (buffer[1] & 0xFF) == 0xFE) {
fprintf(stderr,"discovery packet detected\n");
cmdport = ntohs(client_addr.sin_port);
printf("\nClient connection information:\n\t IP: %s, Port: %d\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
count = sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&client_addr,
sizeof(client_addr));
}
}
}
puts("Now starting command processing loop");
This also works fine... but it sends the reply to the port on the server from which the broadcast came - this was randomly selected automatically by the server; so how do I know what port to listen to on the server side to receive the client's reply?
bind
the socket in the "server" side, so it doesn't get a random port and you can select it yourself. – Some programmer dudegetsockname()
, but you don't need it. – user207421