I'm writing a chat server in c++ for my own amusement, but I'm fairly new to networking in general. My knowledge comes from Beej's guide, this site, and the Top Down approach from Kurose&Ross.
My problem is, that I wrote code veeery similar to the one you can find at the link, but it's not working. The program fails when I try to use the recv() function on the server.
I know recv() can return any number of bytes, but it simply gives me -1. I know I need a loop to piece together the message being sent, but there isn't anything like that just yet. The send() in the client however, says it sent the amount specified in the buffer (yes I know it's probably overkill, not sure if that's a mistake though).
To me it looks like the server is ... closed off somehow ? I'm pretty sure I messed up somewhere, there's a certain line of code I'm really not sure about (look for the comment). I managed to get it work yesterday but something went wrong after that.
I'm really new to socket programming and any kind of networking in general, but the function calls and whatnot came from guides, I have a hunch the problem will be at the part where I specify the ports and addresses, maybe the bytes don't arrive at the server because I'm sending them somewhere else? But if the accept() works, doesn't that mean that a TCP connection is formed, shouldn't i be able to use it after that ?
I'm using Lubuntu linux, the latest release, if that helps.
If you find the problem, can you please tell me how to do it correctly ? Anyways, here's the server's code:
void start() {
char message[1024] = "";
int socketfd = socket( AF_INET, SOCK_STREAM, 0 ), opt = 1, new_socket;
struct sockaddr_in address;
struct sockaddr_storage cl_addr;
socklen_t len = sizeof(address);
if( socketfd != 0 ) {
address.sin_family = AF_INET;
address.sin_port = htons( PORT );
address.sin_addr.s_addr = INADDR_ANY;
if( setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(int)) < 0 ) {
perror("Setsockopt failed");
exit(EXIT_FAILURE);
}
if( bind( socketfd, (struct sockaddr*)&address, len ) < 0 ) {
perror("Couldn't bind to port");
exit(EXIT_FAILURE);
}
if( listen( socketfd, 3 ) < 0 ) {
perror("Listening on port failed");
exit(EXIT_FAILURE);
}
if( (new_socket = accept( socketfd, (struct sockaddr *)&cl_addr, (socklen_t*)&len ) < 0) ) {
perror("Couldn't accept request");
exit(EXIT_FAILURE);
}
/// This is where it fails
std::cout << recv( new_socket, message, 1024, 0) << std::endl;
close(new_socket);
}
else {
perror("Couldn't open socket");
exit(EXIT_FAILURE);
}
close( socketfd );
}
And now the client:
int main(void) {
int sockfd;
struct sockaddr_in serv_addr;
char hello[1024] = "Hello";
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
/// I'm not sure about this !!
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if( sockfd == 0 ) {
perror("Opening socket failed");
exit(EXIT_FAILURE);
}
if( connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) != -1 ) {
/// Says it sent 1024, but sever doesn't recieve it, what gives ?
int test = send( sockfd, hello, sizeof(hello), 0);
std::cout << test << std::endl;
}
else {
perror("Error");
exit(EXIT_FAILURE);
}
As you can see, it's similar to the code found at the link. The server code is just a function, there are other parts of the code like creating user files, but none of them are being used in the networking part, so I didn't feel like posting another 800 lines of code for nothing. The main() of the server is just me creating an object of the server class and calling start() on it.
I'd like to improve where I can, so if you notice something I can do better, please tell me, be it general coding style or anything. Also, It's my first question here ever, and my first language isn't english, please go easy on me :)
It's a parentheses problem.
This line:
if( (new_socket = accept( socketfd, (struct sockaddr *)&cl_addr, (socklen_t*)&len ) < 0) ) {
<
operator has a higher evaluation precedence than the =
operator.
new_socket
is getting assigned the evaluation of accept() < 0
, which is a false expression, so new_socket
gets assigned zero.
This is probably what you meant:
if (new_socket = accept( socketfd, (struct sockaddr *)&cl_addr, (socklen_t*)&len ) < 0)
But this is far less error prone:
new_socket = accept( socketfd, (struct sockaddr *)&cl_addr, (socklen_t*)&len );
if (new_socket < 0) {
perror("Couldn't accept request");
exit(EXIT_FAILURE);
}