I'm trying to test a client-server simple implementation using localhost address.
Here's the code.
Server:
/*
* Sequential busy-waiting
*/
int main(int argc, char** argv) {
int opt, client_addr_l, errsv;
unsigned short port;
struct sockaddr_in server_addr, client_addr;
/* ... */
printf("Port number retrieved (%d), server is starting ...\n", port);
/*TCP Socket creation*/
sock_ds = socket(AF_INET, SOCK_STREAM, 0);
if(sock_ds == -1){
fprintf(stderr, "Socket creation error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
/*Server address binding*/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
/*!!!! */
int optval = 1;
if( (setsockopt(sock_ds,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval))) == -1 ) {
printf("Error on setsockopt\n");
exit(EXIT_FAILURE);
}
/*????*/
if(bind(sock_ds, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
fprintf(stderr, "Address binding error\n");
exit(EXIT_FAILURE);
}
/*Server with passive socket*/
if(listen(sock_ds, SOMAXCONN) == -1){
fprintf(stderr, "Listen call error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
while(1){
memset(&client_addr, 0, sizeof(client_addr));
acc_sock_ds = accept(sock_ds, (struct sockaddr *)&client_addr, &client_addr_l);
printf("DEBUG: LINE201, acc_sock_ds = %d\n", acc_sock_ds);
/*Connect error management*/
if(acc_sock_ds == -1){
fprintf(stderr, "Fatal error on accept %d(%s)\n"
, errsv, strerror(errsv));
exit(EXIT_FAILURE);
}
//sin_addr to ASCII (string) );
printf("Connected with: %s\n", inet_ntoa(client_addr.sin_addr));
/*...*/
close(acc_sock_ds);
/*...*/
}
/*...*/
}
Client:
int main(){
int sock_ds;
struct sockaddr_in remote_addr;
struct hostent *hp;
/*TCP Socket creation*/
sock_ds = socket(AF_INET, SOCK_STREAM, 0);
if(sock_ds == -1){
fprintf(stderr, "Socket creation error\n");
exit(EXIT_FAILURE);
}
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(25556);
hp = gethostbyname("localhost");
bcopy(hp -> h_addr, &remote_addr.sin_addr, hp -> h_length); //fills address entry
if(connect(sock_ds, (struct sockaddr*)&remote_addr, sizeof(remote_addr)) == -1){ //connection attempt
fprintf(stderr, "Connect failure(%s)\n", strerror(errno));
exit(EXIT_FAILURE);
}
/*...*/
}
When i run them on two different terminals server returns me:
Port number retrieved (25556), server is starting ...
Server is ready. Waiting for client connections.
DEBUG: LINE201, acc_sock_ds = 4
Connected with: 0.0.0.0
My question is: why does the client address retrieved by the server is 0.0.0.0. It should not be 127.0.0.1?
It looks like you are passing the third parameter to accept() uninitialized, it should be set at the size of the second parameter. In addition to that, it should be a socklen_t, not an int, see http://pubs.opengroup.org/onlinepubs/009695399/functions/accept.html
Could try by declaring client_addr_l as a socklen_t, then setting it to sizeof( struct sockaddr_in) before passing to accept() ?
I'm guessing its unitialized value is zero, so accept() cannot set the remote address to your client_addr as it has a zero size. So, client_addr is untouched and, as you zeroed it earlier, you get 0.0.0.0.
0.0.0.0 means that your server accept connection from any interface in your equipment
so the loopback interface with the address 127.0..0.1 is included
It seems to be a special situation. All possible addresses are listening for your connection.
Here is a thread on this.
Quote:
0.0.0.0, in this context, means "all IP addresses on the local machine"
(in fact probably, "all IPv4 addresses on the local machine").
So, if your webserver machine has two ip addresses, 192.168.1.1 and 10.1.2.1,
and you allow a webserver daemon like apache to listen on 0.0.0.0,
it will be reachable at both of those IPs.
But only to what can contact those IPs and the web port(s).
server_addr.sin_addr.s_addr = INADDR_ANY;
probably should be
server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
Related
I am currently coding a small chat application in C for learning network.
I develop using the Transmission Control Protocol with socket in C. I was able to connect to my server with a client not coded by myself (on local network). Now telnet succeed to connect to my chat server(so with server and telnet client on the same computer) and I can send and receive message BUT my very simple client cannot connect to it.
Since the begining I use port 9002 and right now I am trying to connect with IPv6 address ::1.
Here the "accept client" code of my server:
int main(void)
{
//Create the socket
int sock = socket(AF_INET6, SOCK_STREAM, 0);
printf("Socket créer\n");
//Set up the socket interface
struct sockaddr_in6 sin6 = { 0 };
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(PORT);
sin6.sin6_addr = in6addr_any;
//Bind the socket on the port
if(bind(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr_in6)) == SO_ERROR)
{
perror("bind()");
errx(EXIT_FAILURE, "Fail to bind");
}
//Make the sockey listen the port
if(listen(sock, MAX_CLIENT) == SO_ERROR)
{
perror("listen()");
errx(EXIT_FAILURE, "Fail to listen");
}
printf("Socket listening\n");
int csock;
size_t clientID = 0;
--snip--
while(1)
{
struct sockaddr_in6 csin6;
memset(&csin6, 0, sizeof(struct sockaddr_in6));
int sin6size = sizeof(struct sockaddr_in6);
//Accept a communication
printf("Wait for communication\n");
csock = accept(sock, (struct sockaddr *) &csin6, &sin6size);
printf("Connection accepted\n");
char msg[16];
sprintf(msg, "CONNECTED - %zu\n", clientID);
send(csock, msg, sizeof(msg), 0);
printf("Client %zu connected\n", clientID);
//Handle client
--snip--
}
So this is a basic connection with socket using connected communication. The server handle several client in the while loop thanks to threading.
Here the code of the client:
void *sender(void *arg)
{
int socket = (int)(long)arg;
char buffer[BUFF_SIZE];
while(1)
{
scanf("%s", buffer);
send(socket, buffer, strlen(buffer), 0);
bzero(buffer, BUFF_SIZE);
}
}
int main(int argc, char *argv[])
{
if(argc < 2)
errx(EXIT_FAILURE, "Usage: ./client <server ip>\n");
//Create the socket
int sock = socket(AF_INET6, SOCK_STREAM, 0);
struct hostent *hostinfo = NULL;
hostinfo = gethostbyname2(argv[1], AF_INET6);
if(hostinfo == NULL)
errx(EXIT_FAILURE, "Can't connect to the server\n");
//Set up the socket interface
struct sockaddr_in6 sin6 = { 0 };
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(PORT);
sin6.sin6_addr = *(struct in6_addr *)hostinfo->h_addr;
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
{
perror("connect()");
errx(EXIT_FAILURE, "Fail to connect");
}
printf("Connection established\n");
pthread_t sending;
if(pthread_create(&sending, NULL, sender, (void *)(long)sock) != 0)
printf("Fail to create a thread\n");
//Handle reception
char buffer[BUFF_SIZE];
int n;
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
{
buffer[n] = '\0';
printf("%s", buffer);
}
printf("Erreur: %d\nConnection broken\n", n);
pthread_cancel(sending);
close(sock);
return EXIT_SUCCESS;
}
So I start the client with:
~ ./client ::1
The output is the following:
Connection established
Error: -1
Connection broken
While the server is still "Waiting for communication". This means that the server do not accept the connection but the client succeed to connect.
Thank you for you help.
It is probably already the connect(), which fails here:
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
SO_ERROR is not meant to be used here, but as a socket option when retrieving the error when an asynchronous connect fails. A (synchronous) connect() returns -1 on error and sets errno, so do
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == -1) {
...
Later, the recv here:
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
fails with errno ENOTCONN, since the connection failed beforehand.
The same SO_ERROR mistake is present at various locations in your server code; it is possible, that already the bind() there fails! The call to listen() will then autobind it to a free ephemereal port, so the call as well as the call to accept() will succeed.
Why can the call to bind() fail? You might have to set the socket option SO_REUSEADDR when (re-)starting the server, otherwise it might refuse to use a recently bound port if connections are still in TIME_WAIT state. Place this directly before the bind() call:
int one = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
This might help.
Basically my server/client socket functions work perfectly fine using the loopback address, or even my eth0 address on my laptop. Howver, once I move my code into the test environment it will be used in, I get connection time outs, or connection refused depending on the changes I have tried to make.
As of now the code I am about to post results in a Connection time out.
CLIENT
void buildConnection(int* txmt_sock, Connection conn_info)
{
struct sockaddr_in servinfo; /* server address */
servinfo.sin_family = AF_INET;
servinfo.sin_addr.s_addr = INADDR_ANY;
servinfo.sin_port = htons(conn_info.port);
if(inet_aton(conn_info.ip, &servinfo.sin_addr) < 1)
{
fprintf(stderr, "Read error: %s\n", strerror(errno));
abort();
}
/*int socket(int domain, int type, int protocol)*/
if ((*txmt_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("client: socket");
abort();
}
/*int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);*/
if (connect(*txmt_sock,(struct sockaddr *)&servinfo,(socklen_t)sizeof(servinfo)) == -1)
{
close(*txmt_sock);
perror("client: connect");
abort();
}
printf("Successfully connected on port %s:%d\n", conn_info.ip, conn_info.port);
}
SERVER
void returnConnection(Connection* conn_info)
{
int status, ext_conn, yes = 1;
char portStr[5];
struct addrinfo hints, *servinfo;
struct sockaddr_storage ext_addr;
socklen_t addr_size;
struct sockaddr *restrict;
/* Formats PORT for use with getaddrinfo(), can't cast #define*/
snprintf(portStr, 6, "%d", conn_info->port);
memset(&hints, 0, sizeof(hints)); /*make sure the struct is empty*/
hints.ai_family = AF_UNSPEC; /*don't care IPv4 or IPv6*/
hints.ai_socktype = SOCK_STREAM; /*TCP stream sockets*/
hints.ai_flags = AI_PASSIVE; /*fill in my IP for me*/
if ((status = getaddrinfo(NULL, portStr, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
if((conn_info->listen_sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1)
{
fprintf(stderr, "Socket error: %s\n", strerror(errno));
exit(1);
}
if(setsockopt(conn_info->listen_sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
if(bind(conn_info->listen_sock, servinfo->ai_addr, servinfo->ai_addrlen) == -1)
{
fprintf(stderr, "Bind error: %s\n", strerror(errno));
exit(1);
}
freeaddrinfo(servinfo);
if(listen(conn_info->listen_sock, 1) == 1)
{
fprintf(stderr, "Listening error: %s\n", strerror(errno));
exit(1);
}
addr_size = sizeof(ext_conn);
if((ext_conn = accept(conn_info->listen_sock, (struct sockaddr *)&ext_addr, &addr_size)) == -1)
{
fprintf(stderr, "Accept error: %s\n", strerror(errno));
exit(1);
};
conn_info->receiving_sock = ext_conn;
}
This is a multi-threaded program that collects image data from 8 different ports/threads. I use my Connection struct to store all the pertinent data for each thread. Each thread has it's own Connection.
typedef struct connection{
char* file;
int port;
char* ip;
pthread_t *thread;
}Connection;
Connection->ip is not used in the server side, but is uses on the Client side. The server side of the code resides on a multi-cpu, multi-nic IBM server. I am not certain if I need to manually assign the IP or not because of that. I am assuming the OS and network cards manage on their own using the incoming PORT numbers from the clients, and the individual PORT numbers that my Server threads listen on. But all I know is that it works on my laptop to itself.
It's a completely new vanilla install on this machine with openSuse, so I don't think any of the ports I am using, 5050-5053 and 5055-5058, are turned off or anything like that.
I am writing a small socket program in C. In server side I create a socket descriptor using socket() system call, then I am binding that socket with a port. After this I am trying to get the IP/Port no of the descriptor, it gives port no different then the bind port no. I am trying to get back IP/Port using getsockname() method, Is it right to use this method ? Please help me.
#define SERVER_ADDR "127.0.0.1"
#define SERVER_PORT "9090" // actual port no I am binding
#define QUEUE_LENGTH 10
int main()
{
struct addrinfo hints, *servinfo, *temp;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
// here I am passing SERVER_PORT == 9090
int status = getaddrinfo(SERVER_ADDR,SERVER_PORT,&hints,&servinfo);
if(status != 0)
{
printf("Server: getaddrinfo() errored with code %d\n",status);
return;
}
int sfd = -1;
for(temp = servinfo; temp != NULL; temp = servinfo->ai_next)
{
sfd = socket(temp->ai_family,temp->ai_socktype,temp->ai_protocol);
if(sfd == -1)
{
printf("Server: Socket error with code %d\n",sfd);
continue;
}
status = bind(sfd,temp->ai_addr,temp->ai_addrlen);
if(status == -1)
{
printf("Server: Bind error with code %d\n",status);
continue;
}
printf("Server: Bind Successful\n");
// un necessary code goes here
struct sockaddr_in server_address;
char ipv4[INET_ADDRSTRLEN];
int addr_size = sizeof(server_address);
// i am using below method to get the port no from socket descriptor
getsockname(sfd, (struct sockaddr *)&server_address, &addr_size);
// I am expecting below will print 9090. but it prints different port no why ?
printf("Server Port: %d\n",server_address.sin_port);
printf("Port from getsddrinfo: %d\n",( (struct sockaddr_in *)temp->ai_addr)->sin_port);
inet_ntop(AF_INET, &(server_address.sin_addr),ipv4,INET_ADDRSTRLEN);
printf("Server IP Address: %s\n",ipv4);
// un necessary code ends here
break;
}
if(temp == NULL)
{
printf("Server: Failed to bind\n");
return;
}
status = listen(sfd,QUEUE_LENGTH);
if(status == -1)
{
printf("Server: Listening failed\n");
return;
}
printf("Server: waiting for coneections...\n");
while(1)
{
printf("Server: Main loop, will wait for client to connect...\n");
struct sockaddr client_address;
int addr_length = sizeof client_address;
// accepting client
int new_sfd = accept(sfd,&client_address,&addr_length);
}
printf("Server: Done!\n");
}
Output is:
Server: Bind Successful
Server Port: 33315 --> why this different from one I have binded (9090)
Port from getsddrinfo: 33315 --> why this different from one I have binded (9090)
Server IP Address: 127.0.0.1
Server: waiting for coneections...
Server: Main loop, will wait for client to connect...
The decimal members of struct sockaddr are returned in network byte order.
So you need to convert such values to host byte order, using the ntoh family of functions before using them, printing them.
add hints.sin_port = htons( 9090 );after hints.ai_socktype = SOCK_STREAM;
I'm making a client program in C that has to deal with this situation:
1- server program receives udp datagram in port no 8080 sent by client with a port number X
2- server creates a new socket (TCP) in port number X
3- using this TCP socket, server reads a string sent by the client
(running on localhost)
I don't need to make the server program, it's already done. The points 1 and 2 are covered, but I've been a couple of days trying to work out the 3rd point and I'm not able to make it work ><
The code I've got for the client is this:
#define MYPORT 8080
int main(int argc, char *argv[ ]) {
int sockfd;
/* connector’s address information */
struct sockaddr_in their_addr;
struct hostent *he;
int numbytes;
int sockfd2, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc != 3) {
fprintf(stderr, "Usage: %s <hostname> <message>\n", argv[0]);
exit(1);
}
/* get the host info */
if ((he = gethostbyname(argv[1])) == NULL) {
perror("Error obtaining the client. \n");
exit(1);
}
else printf("Client obtained\n");
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Error creating UDP socket\n");
exit(1);
}
else printf("UDP Socket done\n");
their_addr.sin_family = AF_INET;
printf("Port: 8080\n");
their_addr.sin_port = htons(MYPORT);
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
memset(&(their_addr.sin_zero), '\0', 8);
sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd2 < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
//sending port where the TCP socket will be associated
//server client connects correctly to this port
//and the code it's working fine in this point
if((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1)
{
perror("Client-sendto() error lol!");
exit(1);
}
//port is sent, now let's connect to the port by tcp and write the string
//not working properly from now on
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(atoi(argv[2]));
if (bind(sockfd2,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
listen(sockfd2, 5);
accept(sockfd2, 0, 0);
printf("accepted!\n");
//sending the string to the TCP Port...
if((numbytes = sendto(sockfd2, "hi", 2, 0, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr))) == -1)
{
printf("Client-sendto()-TCP error\n");
exit(1);
}
if (close(sockfd) != 0) printf("Client-sockfd-UDP closing is failed!\n");
else printf("Client-sockfd-UDP successfully closed!\n");
if (close(sockfd) != 0) printf("Client-sockfd2-TCP closing is failed!\n");
else printf("Client-sockfd2-TCP successfully closed!\n");
return 0;
}
The code works for the first two steps, but in the last step, it seems it's not connecting well with the TCP port, because my client program ends but my server program says that he receives null.
And of course I'm always sending ports > 1024
Thanks in advance, any help will be so appreciated.
listen(sockfd2, 5);
accept(sockfd2, 0, 0);
printf("accepted!\n");
I haven't read all your code, but the above (at least) is wrong. You absolutely need to retain the return value of accept: it's the socket you need to write to!
accept returns a file descriptor for the new TCP socket that has just been created for communicating with the "server" in your case. You need to use that as the file descriptor you write your string to.
(The sendto call just after that, apart from using the wrong socket, is a bit suspicious since the server will have no way to determine how much data to read/where the message stops. Passing a length of 3 (to include the \0 byte, would be a bit less suspicious.)
This is the main code of my server program in C:
int main(int argc, char** argv)
{
int sock, connected, bytes_received, true = 1;
struct sockaddr_in server_addr, client_addr;
int sin_size;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket");
exit(1);
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof (int)) == -1) {
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[1]));
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero), 8);
if (bind(sock, (struct sockaddr *) &server_addr, sizeof (struct sockaddr))
== -1) {
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1) {
perror("Listen");
exit(1);
}
printf("\nTCPServer Waiting for client on port 5000");
fflush(stdout);
while (1)
{
pthread_t child;
sin_size = sizeof (struct sockaddr_in);
connected = accept(sock, (struct sockaddr *) &client_addr, &sin_size);
printf("\n I got a connection from (%s , %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
threadInfo info;
info.argumentsPassedToCode = argv;
info.connected = connected;
pthread_create(&child, NULL, interpretMessage, &info);
}
close(sock);
return 0;
}
My server always prints out the IP of the incoming connection, and the port that it is coming in from. I noticed that the ports are always increasing.
Is this normal? If not, what am I doing wrong?
If my server runs for a long time, will it run out of ports? If so, what will happen?
If your server is working, you're not doing anything wrong. Source ports aren't guaranteed to follow a pattern, they just exist to complete the connection tuple, (source port, source address, dest port, dest address).
Ports are reused once connections close, so you should be okay.
TCP has a state called TIME_WAIT which is used to make sure that everything have been sent and received properly before cleaning up the socket. This happens after you have closed the socket in you code. The time that a socket is in the TIME_WAIT state depends on the OS.
That's why you don't get the same port again for client connections.
You can read more about the state here: https://stackoverflow.com/questions/41602/how-to-forcibly-close-a-socket-in-time-wait
1) Yes; the next available port is selected. It can be the same port (if the prev socket was freed already by kernel), it can be the next free one or any other port which is free, from 1024 to 65535 (first 1024 are reserved as you know); In your case you are seeing a different client port number because either you are not properly closing the client socket or the previous socket is still lingering when you are making the next connection or you are just making multiple parallel connections
2) If you are not properly shutting down the sockets, you will (probably first run out of file descriptor if you have lower default per-process limits which is ... 1024 fds per proc?) ; If you do tear them down correctly then you'll be fine