I'm currently having a problem passing messages between a server and client.
As far as I know, I am properly following best practices for socket programming outlined by Beej's Socket Programming Tutorial.
When I run the two processes, the recv() syscall returns -1 (an error), rather than the number of bytes received. Also when trying to output the buf, there are a bunch of gobbledygook characters. Which makes sense, because of the error.
I'm wondering if someone could steer me in the right direction as to why I am having issues with recv()? The following are relevant code snippets.
Server:
struct sockaddr_storage their_addr;
socklen_t addr_size;
int sockfd, newfd, byte_count, status;
char buf[512];
struct addrinfo hints, *res;
// first, load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// get address info, print stuff if error
if((status = getaddrinfo("nunki.usc.edu", "21957", &hints, &res)) !=0){
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
// make a socket:
if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){
cout << "socket fail" << endl;
}
// bind the socket to the port
bind(sockfd, res->ai_addr, res->ai_addrlen);
// required output
cout << "Phase1: Login server has TCP port number " << "21957 "
<< "and IP address " << getIPfromHost("nunki.usc.edu") << endl;
// listen for incoming connections
listen(sockfd, 10);
cout << "after listen" << endl;
// halt until receipt
addr_size = sizeof(their_addr);
newfd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size);
cout << "after accept" << endl;
// Now that we're connected, we can receive some data
byte_count = recv(sockfd, buf, sizeof buf, 0);
printf("recv()'d %d bytes of data in buf\n", byte_count);
printf("Msg is %s\n", buf);
Client:
struct addrinfo hints, *res;
int sockfd;
// first, load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("nunki.usc.edu", "21957", &hints, &res);
// make a socket:
if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){
cout << "socket fail" << endl;
}
// attempt connection to port
if(connect(sockfd, res->ai_addr, res->ai_addrlen) == -1){
cout << "connect fail" << endl;
}
// send message to server
cout << "sockfd " << sockfd << endl;
int byte_count = send(sockfd, "Hello", 5, 0);
cout << byte_count << endl;
The following is the output for Server:
Phase1: Login server has TCP port number 21957 and IP address 68.181.201.3
after listen
after accept
recv()'d -1 bytes of data in buf
Msg is ÿhÿ?sÈ
Glæ
The following is the output for Client:
sockfd 4
5
You are calling recv on the wrong socket. You need to recv on newfd:
byte_count = recv(newfd, buf, sizeof buf, 0); /* newfd instead of sockfd. */
Now that that's out of the way,
As far as I know, I am properly following best practices for socket
programming
I completely disagree.
You are not checking return statuses for listen, bind, getaddrinfo etc
There's not strerror or perror in your program
You want to recv() using the socket returned from accept()
byte_count = recv(newfd, buf, sizeof buf, 0);
Maybe I shouldn't write this as an answer, but as a comment. Nevertheless, IMHO your use of getaddrinfo() seems wrong to me.
On the client side, it is supposed to be called and then iterated through the results until a connection can be established.
so
struct addrinfo * r2
sockfd = -1;
for (r2=res; r2; r2=r2->ai_next) {
// make a socket:
if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){
continue; // next result
}
// attempt connection to port
if(connect(sockfd, res->ai_addr, res->ai_addrlen) == -1){
close(sockfd);
sockfd = -1;
continue;
}
}
if (sockfd == -1) {
// do error handling
}
In this way, you can check all possible connections.
On the server side, it is rather unusual to use getaddrinfo(). Normally, you would create an IPv6 socket and enable it to listen for IPv4 as well by using setsockopt() to unset the IPV6_V6ONLY flag. In this way, the socket listens to both IPv6 and IPv4. (Alas, not on WIndows XP AFAIK.)
The sockfd is just useed for listening the clients, newfd is used for data transmitting.
Related
So, I was trying to code this simple TCP server, but I'm stucked with this error
error: 'inet_ntop' was not declared in this scope; did you mean 'inet_ntoa'
I know that I have to use ntop and not ntoa. But I can't find out how to get rid of this error. I searched everywhere and couldn't find anything. I hope someone can help me. My code is below.
#define _WIN32_WINNT 0x501
#include <iostream>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
int main(void){
//initialize winsock
WSADATA WSData;
WORD ver = MAKEWORD(2, 2);
int WSOK = WSAStartup(ver, &WSData);
if (WSOK != 0){
cerr << "Can't initialize winsock! Quitting" << endl;
return 0;
}
//create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return 0;
}
// bind the socket to an ip adress an port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // could also use inet_pton...
bind(listening, (sockaddr*)&hint, sizeof(hint));
//tell winsock the socket is for listening
listen(listening, SOMAXCONN);
//wait for connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
char host[NI_MAXHOST]; // client's remote name
char service[NI_MAXSERV]; // Service (i.e port) the client is connected on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXSERV);
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
cout << host << "connected on port" << service << endl;
}
else
{
inet_ntop(AF_INET, &client.sin_addr), host, NI_MAXHOST);
cout << host << "connecte on port" <<
ntohs(client.sin_port) << endl;
}
//close listening socket
closesocket(listening);
//while loop: accept and echo message bac to client
char buf[4096];
while (true)
{
ZeroMemory(buf, 4096);
//wait for client send data
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == SOCKET_ERROR)
{
cerr << "Error in recv(). Quitting" << endl;
break;
}
if (bytesReceived == 0)
{
cout << "Client disconnected " << endl;
break;
}
//echo message back to client
send(clientSocket, buf, bytesReceived + 1, 0);
}
//close socket
closesocket(clientSocket);
// cleanup winsock
WSACleanup();
}
inet_ntop() requires Windows Vista and later at runtime, but you are setting _WIN32_WINNT to 0x501, which represents Windows XP, so the declaration of inet_ntop() in <w32tcpip.h> gets disabled at compile-time to prevent the program from failing to start at runtime.
You need to set _WIN32_WINNT to at least 0x600 instead to enable inet_ntop().
However, even after you fix that issue, your code will still fail to compile, because you have a syntax mistake in your call to inet_ntop() - your parenthesis are unbalanced in the 2nd parameter. You have either a missing (, or an erroneous ), depending on which of the following syntaxes you were trying to use:
inet_ntop(AF_INET, &(client.sin_addr), host, NI_MAXHOST);
inet inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
You also have other logic errors that won’t show up until runtime. You are not doing any error handling on bind(), listen(), and send(). And you have a potential buffer overflow on send(), too.
My program is client server IPv6. the client can't make connection to the server? The client and server must use loop-back address
the problem in this code its can't connect to the server
SOCKET sock = socket(AF_INET6, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
cerr << "Can't create socket, Err #" << WSAGetLastError() << endl;
WSACleanup();
return;
}
sockaddr_in6 hint;
hint.sin6_family = AF_INET6;
hint.sin6_port = htons(port);
hint.sin6_addr = in6addr_any;
// Connect to server
int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (connResult == SOCKET_ERROR)
{
cerr << "Can't connect to server, Err #" << WSAGetLastError()
<< endl;
closesocket(sock);
WSACleanup();
return;
}
A client TCP socket cannot connect() to in6addr_any. A TCP server can bind() to in6addr_any so it can then listen() on all available local IPv6 network interfaces with a single SOCKET. But the client must connect() to a real IPv6 address that the server is actually listening on (such as in6addr_loopback if the client is running on the same machine as the server. Your server can use GetAdaptersInfo() or GetAdaptersAddresses() to discover what its local IP addresses actually are that are valid for the client to connect() to).
Also, you need to zero out the sockaddr_in6 struct completely. sockaddr_in6 has sin6_flowinfo and sin6_scope_id fields that you are not populating, so they will have random values from the stack. sin6_scope_id in particular will affect connect()'s ability to use the correct network interface to connect to the server.
SOCKET sock = socket(AF_INET6, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
cerr << "Can't create socket, Err #" << WSAGetLastError() << endl;
WSACleanup();
return;
}
sockaddr_in6 hint = {};
hint.sin6_family = AF_INET6;
hint.sin6_port = htons(port);
inet_pton(AF_INET6, "server IPv6 address here", &(hint.sin6_addr));
// Connect to server
int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
...
Consider using getaddrinfo() instead. Let the OS allocate a properly-populated sockaddr_in6 for you, which you can then pass as-is to connect() (similarly to how I explained to you in your previous question for bind()).
addrinfo hint = {};
hint.ai_family = AF_INET6;
hint.ai.socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
addrinfo *res;
err = getaddrinfo("server hostname or IPv6 address here", "server port here", &hint, &res);
if (err != 0)
{
cerr << "Can't get address to connect, Err #" << WSAGetLastError() << endl;
WSACleanup();
return;
}
SOCKET sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock == INVALID_SOCKET)
{
cerr << "Can't create socket, Err #" << WSAGetLastError() << endl;
freeaddrinfo(res);
WSACleanup();
return;
}
// Connect to server
int connResult = connect(sock, res->ai_addr, res->ai_addrlen);
if (connResult == SOCKET_ERROR)
{
cerr << "Can't connect to server, Err #" << WSAGetLastError() << endl;
closesocket(sock);
freeaddrinfo(res);
WSACleanup();
return;
}
freeaddrinfo(res);
...
I am trying to port ipv4 applications to ipv6 but I can't bind the socket to the ipv6 address.
The problem is here:
err=bind(listening, (sockaddr*)&hint, sizeof(hint));
The err should be 0 but in this code it returns -1. What is going wrong ?
SOCKET listening = socket(AF_INET6, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return;
}
int err;
// Bind the ip address and port to a socket
sockaddr_in6 hint;
hint.sin6_family = AF_INET6;
hint.sin6_flowinfo = 0;
hint.sin6_port = htons(54000);
hint.sin6_addr = in6addr_any;
err=bind(listening, (sockaddr*)&hint, sizeof(hint)); //<======= here
Rather than populate the sockaddr_in6 manually, you can (and should) use getaddrinfo() instead and let it allocate a properly filled sockaddr_in6 for you, eg:
int err;
SOCKET listening = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listening == INVALID_SOCKET)
{
err = WSAGetLastError(); // or errno on non-Windows platforms...
cerr << "Can't create a socket! Error " << err << ". Quitting" << endl;
return;
}
// Bind the ip address and port to a socket
addrinfo hint = {};
hint.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
hint.ai_family = AF_INET6;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
addrinfo *res;
err = getaddrinfo("::0", "54000", &hint, &res);
if (err != 0)
{
cerr << "Can't get address to bind the socket! Error " << err << ". Quitting" << endl;
closesocket(listening); // or close() on non-Windows platforms...
return;
}
err = bind(listening, res->ai_addr, res->ai_addrlen);
if (err == SOCKET_ERROR)
{
err = WSAGetLastError(); // or errno on non-Windows platforms...
cerr << "Can't bind the socket! Error " << err << ". Quitting" << endl;
freeaddrinfo(res);
closesocket(listening); // or close() on non-Windows platforms...
return;
}
freeaddrinfo(res);
...
This might depend on your platform, but on Linux since 2.4 the sockaddr_in6 structure also contains a sin6_scope_id member for defining the IPv6 scope, and since the variable hint is on the stack, it's got random data in it.
The IPv6 scope describes what kind of address it is: unicast, multicast, link local, and a few others, and I have only a drive-by knowledge of them. But if there's garbage in there, it could be a thing.
Recommend ruling this out as an issue by either hard-setting sin6_scope_id to zero, or (better) just zero out the entire sockaddr_in6 structure before assigning stuff to it; I've long done this with my sockaddr_in variables just to be sure I didn't end up with junk I didn't want.
memset(&hint, 0, sizeof hint);
And yes, the errno is really important.
I would like to make non-block TCP receiver so the cilent can send message to server periodically (i.e. update information every 10 minutes).
I test it in a local machine. 'return_status' value indicates that the 'bind, accept, connect and write' are working correctly but the read always return -1. Can someone explain on this? Thanks
Code of client side.
#define CONTROLPORT 6000
int main(void)
{
int control_sock, return_status;
struct sockaddr_in control_addr;
socklen_t control_len;
memset(&control_addr, 0, sizeof(control_addr));
char control_message[10];
control_sock = socket(AF_INET, SOCK_STREAM, 0);
control_addr.sin_family = AF_INET;
control_addr.sin_addr.s_addr = inet_addr("192.168.16.133");
control_addr.sin_port = htons(CONTROLPORT);
return_status = bind(control_sock, (struct sockaddr *) &control_addr, sizeof(control_addr));
fcntl(control_sock, F_SETFL, O_NONBLOCK);
return_status = listen(control_sock, 1);
cout << return_status << endl;
return_status = accept(control_sock, (struct sockaddr *) &control_addr, &control_len);
cout << return_status << endl;
while(1){
return_status = read(control_sock,control_message,sizeof(control_message));
cout << return_status << endl;
}
}
Code of sender side
#define CONTROLPORT 6000
using namespace std;
int main(void)
{
int control_sock, return_status;
struct sockaddr_in control_addr;
socklen_t control_len;
memset(&control_addr, 0, sizeof(control_addr));
char control_message[10];
control_message[10] = 111;
control_sock = socket(AF_INET, SOCK_STREAM, 0);
control_addr.sin_family = AF_INET;
control_addr.sin_addr.s_addr = inet_addr("192.168.16.133");
control_addr.sin_port = htons(CONTROLPORT);
return_status = connect(control_sock, (struct sockaddr *) &control_addr, sizeof(control_addr));
cout << return_status << endl;
return_status = write(control_sock,control_message,sizeof(control_message));
cout << return_status << endl;
}
You have set your socket to non-blocking and as such accept is not going to block until some one connects. accept would be returning EAGAIN or EQOULDBLOCK. Check the errno. Without this checks your code proceeds to do the read. And it returns -1 (again check the errno) since the connections has not been established in the first place.
You have to use select, poll or epoll to see for events on non blocking sockets. That is to figure out if someone is connecting /sending data on established connections.
If you're going to engage in non-blocking socket programming you have to understand that read() is going to return -1 with errno set to EAGAIN/EWOULDBLOCK when there is nothing to read, and use select() to tell you when it won't.
NB 4 is a valid socket FD in Unix, Solaris, HP-UX, AIDA, Linux, ...
In your situation, I don't think non-blocking server is necessary. If you really mean that, you should take a look at select(), epoll and the similar. As to your code, there're several problems:
accept() in the server side should be in the while loop.
accept() returns a descriptor for the accepted socket on success, and this descriptor should pass to read().
As Prabhu's answer says, you have set your socket to O_NONBLOCK, so the accept() would return immediately. If no connections are present to be accepted, the errno would be set to EAGAIN or EWOULDBLOCK.
the code after modification:
int main(void)
{
int control_sock, return_status;
struct sockaddr_in control_addr;
socklen_t control_len;
memset(&control_addr, 0, sizeof(control_addr));
char control_message[10];
control_sock = socket(AF_INET, SOCK_STREAM, 0);
control_addr.sin_family = AF_INET;
control_addr.sin_addr.s_addr = inet_addr("192.168.7.134");
control_addr.sin_port = htons(CONTROLPORT);
return_status = bind(control_sock, (struct sockaddr *) &control_addr, sizeof(control_addr));
//fcntl(control_sock, F_SETFL, O_NONBLOCK);
return_status = listen(control_sock, 1);
cout << return_status << endl;
while(1){
return_status = accept(control_sock, (struct sockaddr *) &control_addr, &control_len);
cout << return_status << endl;
return_status = read(return_status,control_message,sizeof(control_message));
cout << return_status << endl;
}
}
Firstly, the code I will share is the basis of my code(found it in another site, open source), I added functions and threads later to improve.
In the office, we have local network and another 3 computer cannot connect to my server. Especially have a look at that line. 26010 is random port number that I want to listen. According to data I found in the other topics, NULL and 127.0.0.1 are the localhost ip.I tried my own ip number instead of NULL, but it didn't work. I can send data from my client code to other computers, but can't get any connections.
Code is listening connections properly, and can get info if I open another 3 terminal and try to connect it from my computer through my client code. How to fix that?
Thanks in advance.
status = getaddrinfo(NULL, "26010", &host_info, &host_info_list);
int main()
{
int status;
struct addrinfo host_info; // The struct that getaddrinfo() fills up with data.
struct addrinfo *host_info_list; // Pointer to the to the linked list of host_info's.
memset(&host_info, 0, sizeof host_info);
std::cout << "Setting up the structs..." << std::endl;
host_info.ai_family = AF_UNSPEC; // IP version not specified. Can be both.
host_info.ai_socktype = SOCK_STREAM; // Use SOCK_STREAM for TCP or SOCK_DGRAM for UDP.
host_info.ai_flags = AI_PASSIVE;
**status = getaddrinfo(NULL, "26010", &host_info, &host_info_list);**
// getaddrinfo returns 0 on succes, or some other value when an error occured.
// (translated into human readable text by the gai_gai_strerror function).
if (status != 0) std::cout << "getaddrinfo error" << gai_strerror(status) ;
std::cout << "Creating a socket..." << std::endl;
int socketfd ; // The socket descripter
socketfd = socket(host_info_list->ai_family, host_info_list->ai_socktype,
host_info_list->ai_protocol);
if (socketfd == -1) std::cout << "socket error " ;
std::cout << "Binding socket..." << std::endl;
int yes = 1;
status = setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
status = bind(socketfd, host_info_list->ai_addr, host_info_list->ai_addrlen);
if (status == -1) std::cout << "bind error" << std::endl ;
std::cout << "Listen()ing for connections..." << std::endl;
status = listen(socketfd, 5);
if (status == -1) std::cout << "listen error" << std::endl ;
int new_sd;
struct sockaddr_storage their_addr;
socklen_t addr_size = sizeof(their_addr);
new_sd = accept(socketfd, (struct sockaddr *)&their_addr, &addr_size);
if (new_sd == -1)
{
std::cout << "listen error" << std::endl ;
}
else
{
std::cout << "Connection accepted. Using new socketfd : " << new_sd << std::endl;
}
std::cout << "Waiting to recieve data..." << std::endl;
ssize_t bytes_recieved;
char incomming_data_buffer[1000];
bytes_recieved = recv(new_sd, incomming_data_buffer,1000, 0);
// If no data arrives, the program will just wait here until some data arrives.
...
std::cout << "send()ing back a message..." << std::endl;
return 0 ;
}
Your problem is your call to getaddrinfo(). This function returns information in the host_info_list member. What you're reading is the hint (host_info) which is not changed by getaddrinfo(). You would need to use host_info_list to read the what's returned by getaddrinfo. You never use it and you never free it (by calling freeaddrinfo).
I am not sure why you'd want to use getaddrinfo() to listen for connection. You can just build the sockaddr yourself. It's easy:
struct sockaddr_in listenAddr;
memset(&listenAddr, 0, sizeof(listenAddr));
/* IPv4 address */
listenAddr.sin_family = AF_INET;
/* your port number */
listenAddr.sin_port = htons(26010);
/* listen on all interfaces */
listenAddr.sin_addr.s_addr = htonl(INADDR_ANY);
/* TCP socket */
socketfd = socket(PF_INET, SOCK_STREAM, 0);
/* your error code, omitted here */
status = bind(SocketFD,(struct sockaddr *) &listenAddr, sizeof(listenAddr))