I'm trying to write a c++ winsock client/server pair. Everything I've read online has the client supply the IP to connect to via command line argument. Nothing says how to get THE (singular) IP address of the server. I know how to get a list of them, but cant find anything about finding the right one. THE IMPORTANT PART I need the IP address the client needs to connect to the server from a different computer on a different network.
Also, nothing seems too keen on explaining how to supply one to getaddrinfo ie. what data type do I use?
Any help/links to resources are welcome, Thanks, Peter
EDIT (in response to comments about clarity): I have a datagram/UDP server class. Its all set up to recv from a socket. I know which socket. The problem is that I dont know what the IP is to provide the client so it can connect to the server. (Once the client is connected I know how to obtain the IP of the host but not before then which is a real problem as it precludes the client from connecting at all.)
Problem 2: Once I have this IP address, how do I supply it to getaddrinfo? I dont want to use command line arguments. Do I have the user std::cin the IP to a char array? How long do I need that array to be and are there any special termination characters I need to add to the end?
Hope this is more clear.
And just for kicks here's my code. Its all in one file so everything I have is here:
#include <stdio.h>
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <cstring>
#pragma comment(lib, "ws2_32.lib")
#define PORT "4590"
#define MAXBUFLEN 100
void startup(){
WSADATA wsaData;
int iResult;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0){
fprintf(stderr, "WSAStartup failed\n");
exit(1);
}
}
void cleanup(){
WSACleanup();
}
bool getIsHost(){
int hosting;
printf("Are you the host or the client? (1=host, 0=client) ");
std::cin >> hosting;
if (hosting != 0){
return true;
}
return false;
}
void *get_in_addr(struct sockaddr *sa){
if (sa->sa_family == AF_INET){
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
void printNetworkAddress(){
std::cout << "Getting Host Name" << std::endl;
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR){
std::cerr << "Error " << WSAGetLastError() << " when getting local host name." << std::endl;
exit(1);
}
std::cout << "Host name is " << ac << "." << std::endl;
struct hostent *phe = gethostbyname(ac);
if (phe == 0){
std::cerr << "Bad host lookup." << std::endl;
exit(1);
}
for (int i = 0; phe->h_addr_list[i] != 0; ++i){
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
std::cout << "Address " << i << ": " << inet_ntoa(addr) << std::endl;
}
}
void serverFunction();
void clientFunction();
int main(){
bool isHost;
// Header
printf("Client/Server Program\n");
isHost = getIsHost();
startup();
if (isHost){
serverFunction();
}
else{
clientFunction();
}
cleanup();
printf("\n");
std::cin >> isHost;
return 0;
}
void serverFunction(){
printf("Setting up Server\n");
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv; // Error checking on getaddrinfo
int numbytes;
struct sockaddr_storage their_addr;
char buf[MAXBUFLEN];
socklen_t addr_len;
char s[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
cleanup();
exit(1);
}
for (p = servinfo; p != NULL; p = p->ai_next){
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
closesocket(sockfd);
perror("listener: bind");
}
break;
}
if (p == NULL){
fprintf(stderr, "listener: failed to bind socket\n");
exit(2);
}
printNetworkAddress();
freeaddrinfo(servinfo);
printf("listener: waiting to recvfrom ... \n");
addr_len = sizeof their_addr;
if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN - 1, 0, (struct sockaddr *)&their_addr, &addr_len)) == -1){
perror("recvfrom");
cleanup();
exit(1);
}
printf("listener: got packet from %s\n", inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s));
printf("listener: packet is %d bytes long\n", numbytes);
buf[numbytes] = '\0';
printf("listener: packet contains\"%s\"\n", buf);
closesocket(sockfd);
}
void clientFunction(){
printf("Setting up Client\n");
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
char connectaddr[16];
memset(connectaddr, 0, sizeof connectaddr);
printf("connectaddr len: %u\n", strlen(connectaddr));
std::cout << "Enter the host IP Address: ";
std::cin >> connectaddr;
printf("connectaddr len: %u\n", strlen(connectaddr));
//connectaddr[strlen(connectaddr)] = '\0';
if ((rv = getaddrinfo(connectaddr, PORT, &hints, &servinfo)) != 0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(1);
}
for (p = servinfo; p != NULL; p = p->ai_next){
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
break;
}
if (p == NULL){
fprintf(stderr, "talker: failed to bind socket\n");
exit(2);
}
char message[256];
std::cout << "Enter your message: ";
std::cin >> message;
if ((numbytes = sendto(sockfd, message, strlen(message), 0, p->ai_addr, p->ai_addrlen)) == -1) {
perror("talker: sendto");
exit(1);
}
freeaddrinfo(servinfo);
printf("talker: sent %d bytes to %s\n", numbytes, connectaddr);
closesocket(sockfd);
}
getaddrinfo
implying you just want to do a hostname to IP address lookup? At some point you're going to have to put an IP or hostname into a config file, on the command line, or hardcode it into your game. \$\endgroup\$