I got an interview question in sockets in c programming I got two files server.c and client.c
I was asked what will happen if you run a client when the server is not running : more specifically
run
./client localhost
without running./server
in a different terminal
and I didn't know the answer (obviously it won't connect but what will happen I don't know) they wanted an answer that was related to the sockets
when I checked in Wireshark to see if I can get some information I saw this:
the focus on the red record of the TCP sockets and the one record above it.
9999 is the port of the server what is the meaning of every parameter here?
56020 ->9999 [SYN] Seq=0 Win=65495 Len=0 MSS=65495 SACK_PERM=1 TSval=736093598 TSecr=0 WS=128
and also what is the meaning of
9999 -> 56020 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
I tried to look for the meaning in google but didn't find results that related to sockets. thank you very much in advanced!
code for the client.c
// to run in the terminal compile with
// gcc -o client client.c -Wall
// then run the following command:
// ./client localhost
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SIM_LENGTH 10
// #define IP_ADDRESS "127.0.0.1" // from the last part we put this in comment and resolve it with gethostbyname
#define PORT 9999
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in cli_name;
int count;
int value;
char *hostname;
char *hostaddr;
struct addrinfo *res;
struct sockaddr_in *saddr;
printf("Client is alive and establishing socket connection.\n");
printf("%d %s\n", argc, argv[1]);
if (argc != 2)
{
perror("Usage: hostnamelookup <hostname> error \n");
exit(1);
}
hostname = argv[1]; // hostname is the first argument
printf("Hostname is %s\n", hostname);
if (0 != getaddrinfo(hostname, NULL, NULL, &res)) // getaddrinfo is a function that returns a struct addrinfo* that
// contains a linked list of struct addrinfo (from nslookup.c)
{
fprintf(stderr, "Error in resolving hostname %s\n", hostname);
exit(1);
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror("Error opening channel");
close(sock);
exit(1);
}
saddr = (struct sockaddr_in *)res->ai_addr; // get the address of the server socket address structure (from nslookup.c)
hostaddr = inet_ntoa(saddr->sin_addr); // get the IP address of the server (from nslookup.c)
bzero(&cli_name, sizeof(cli_name));
cli_name.sin_family = AF_INET;
cli_name.sin_addr.s_addr = inet_addr(hostaddr); // set the IP address of the client (from nslookup.c)
cli_name.sin_port = htons(PORT);
if (connect(sock, (struct sockaddr *)&cli_name, sizeof(cli_name)) < 0)
{
perror("Error establishing communications");
close(sock);
exit(1);
}
for (count = 1; count <= SIM_LENGTH; count )
{
read(sock, &value, 4);
printf("Client has received %d from socket.\n", value);
}
printf("Exiting now.\n");
close(sock);
exit(0);
}
server.c
// to run in the terminal compile with
// gcc -o server server.c -Wall
// then run the following command:
// ./server
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SIM_LENGTH 10
#define PORT 9999
int main(void)
{
int sock; // socket descriptor
int connect_sock; // socket descriptor for the connection
struct sockaddr_in serv_name; // server socket address structure
socklen_t len; // length of the socket address structure
int count; // number of bytes received
sock = socket(AF_INET, SOCK_STREAM, 0); // create a socket
// check if the socket is valid
if (sock < 0)
{
perror("Error opening channel");
exit(1);
}
// initialize the server socket address structure
bzero(&serv_name, sizeof(serv_name)); // clear the structure
serv_name.sin_family = AF_INET; // set the family to Internet
serv_name.sin_port = htons(PORT); // set the port number
// check if the bind is successful
if (bind(sock, (struct sockaddr *)&serv_name, sizeof(serv_name)) < 0) // bind the socket to the server address
{
perror("Error on binding");
exit(1);
}
// listen for connections
if (listen(sock, 1) < 0) // listen for connections on the socket
{
perror("Error on listening");
exit(1);
}
len = sizeof(serv_name); // get the length of the socket address structure
connect_sock = accept(sock, (struct sockaddr *)&serv_name, &len); // accept a connection on the socket
// check if the connection is valid
if (connect_sock < 0)
{
perror("Error on accepting");
exit(1);
}
for (count = 1; count <= SIM_LENGTH; count ) // loop to send the data
{
write(connect_sock, &count, 4); // send the data
printf("Server has written %d to socket.\n", count); // print the data
}
close(connect_sock); // close the connection
close(sock); // close the socket
}
CodePudding user response:
If the host on that IP is completely down and unreachable (or the destination port is effectively firewalled), then the client will retry initiating the three way handshake a few times before timing out and bubbling up an error to the socket application calling connect
.
If the host is up, but not listening on the expected port, it will send back an RST
in response to receiving SYN
from the client. That will effectively tell the client to "go away, I'm not listening". And the TCP stack will again bubble up an error to the socket application to trigger its connect
call to return an error.