Pete
Pete

Reputation: 1561

c socket port number as cmd line argument is changed?

I'm writing my first C program with sockets. I want my server program to take the TCP port number as the only command line argument. Here's a condensed version of my code (compiled on GCC, running on Linux):

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{

  int listenfd = 0;
  struct sockaddr_in serv_addr;

  listenfd = socket(AF_INET, SOCK_STREAM, 0);

  memset(&serv_addr, '0', sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  printf("Server::  About to set %hu as the port...\n", (unsigned short)strtoul(argv[1], NULL, 0));
  serv_addr.sin_port = htons((unsigned short)strtoul(argv[1], NULL, 0));

  bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

  printf("Server::  About to listen on port %hu...\n", serv_addr.sin_port);
  listen(listenfd, 10);

}

Output of this program is:

[Linux]$ ./server.exe 12345
Server::  About to set 12345 as the port...
Server::  About to listen on port 14640...
^C
[Linux]$

As you can see, I'm trying to tell the server that I want TCP port 12345, but it is somehow getting garbled into TCP port 14640. Not surprisingly, when I run my client program (./client.exe 127.0.0.1 12345), the client gets a "Connection Refused," meaning no-one is listening on port 12345. Ditto if I run (./client.exe 127.0.0.1 14640).

So I'm scratching me head on this one. I'm assuming this is some kind of casting or data handling issue, because if replace this line:

serv_addr.sin_port = htons((unsigned short)strtoul(argv[1], NULL, 0));

with this:

serv_addr.sin_port = htons(12345);

(aka, hardcode the TCP port), the socket works fine and client & server can communicate all they want.

A little Internet research tells me that the TCP port is stored as a unsigned short in the struct sockaddr_in and that's why my code is bending over backwards to hammer the data into the right format. I've tried a lot of other ways to massage the port number; trying to use atoi(argv[1]) and then casting the returned integer as an unsigned short, for example, gives the exact same result.

Any advice? Is this an htons() issue? A formatting or casting issue?

Thanks, -RAO

Upvotes: 2

Views: 3633

Answers (2)

Bharadwaj S
Bharadwaj S

Reputation: 21

Try this:

addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[1]));
addr.sin_addr.s_addr = inet_addr(*(argv+2));

It worked for me. atoi() accepts integers and inet_addr() accepts strings as arguments. Make sure you pass a string to inet_addr() failing which also may refuse connection

Upvotes: 2

David Schwartz
David Schwartz

Reputation: 182753

 printf("Server::  About to listen on port %hu...\n", serv_addr.sin_port);

That doesn't work. The %hu format specifier is for unsigned integers in native format. The sin_port field is not in native format, it's in network format. So you can't print it this way.

You can convert it into native byte order with ntohs and then print it, if you want:

printf("Server::  About to listen on port %hu...\n", ntohs(serv_addr.sin_port));

Upvotes: 4

Related Questions