How to connect a TCP server to another TCP server - c

I'm working with TCP servers. Let's say I have a server running with a specific port, but then I want to connect a client to it, I would simply go through the typical procedure of socket, bind, listen, accept for the server and then socket, connect for the client. So let's say our server port is 4000, and our client port 4001. Now, I want to create a new client that will connect to my client on port 4001, but to my limited understanding, I cannot do this as a client. Port 4001 would have to pertain to a server and not a client (i.e. it would have to be listening). The issue arises because I don't think you can use the same port for both the server and client.
I've decided to attempt this through the sample code I've provided below. I call the program on the command line as follows:
If this is the first call of the server, then I simply call the program without any arguments and it will automatically run on port 3000. i.e. ./serverprogram
If I would like to connect a client on port 3001 to our server on port 3000. Then I would call the command line with two arguments, the first being 3001 and the second being 3000. i.e. ./serverprogram 3001 3000
#define PORT 3000
int main (int argc, char * argv[]){
int sfd = socket(AF_INET, SOCK_STREAM, 0);
int my_port = (argc == 3) ? atoi(argv[1]) : PORT;
if (argc > 2){
struct sockaddr_in c_addr;
c_addr.sin_family = AF_INET;
memset(&c_addr.sin_zero, 0, 8);
c_addr.sin_port = htons(atoi(argv[2]));
struct addrinfo *result = NULL;
getaddrinfo("AcaciaLinux", NULL, NULL, &result);
struct sockaddr_in *x = (struct sockaddr_in*) result->ai_addr;
c_addr.sin_addr = x->sin_addr;
freeaddrinfo(result);
if(connect(sfd, (struct sockaddr *) &c_addr, sizeof(struct sockaddr_in)) == -1){
perror("connect");
exit(1);
}
printf("We have connected to a server.");
}
if (sfd == -1){
perror("socket");
exit(1);
}
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(my_port);
saddr.sin_addr.s_addr = INADDR_ANY;
memset(&(saddr.sin_zero), 0, 8);
if(bind(sfd, (struct sockaddr*) &saddr, sizeof(struct sockaddr_in)) == -1){
perror("bind");
close(sfd);
exit(1);
}
if (listen(sfd, 5) < 0){
perror("listen");
exit(1);
}
struct sockaddr_in caddr;
saddr.sin_family = AF_INET;
int cfd;
unsigned int c_len = sizeof(struct sockaddr_in);
if ((cfd = accept(sfd, (struct sockaddr*) &caddr, &c_len)) == -1){
perror("accept");
exit(1);
}
printf("Alas, we have finally connected to a client.");
return 0;
}
Upon running the second instance of the program I receive the error "bind: Invalid argument". I am assuming that this is due to the fact that the port is already in use. Is there any way to bypass this, or is there any way to connect a server to a client, and allow the client to also act as a server using the same port

You cannot open a socket which can do the both listen and connect.

A TCP connection is identified by its two endpoints. Each of those, in turn, is identified by an (IP address, port) pair. Therefore, you cannot simultaneously have two distinct connections between the same two IP addresses with the same ports on each end -- if all of those properties are the same, then they are the same connection.
From the perspective of system interfaces, you cannot create that situation because the system will not allow you to bind an address / port pair that is already in use to any socket (a stronger constraint than is strictly required). This means that one machine cannot use the same port simultaneously for both a client socket and a server socket, even for different remote endpoints.
You can, however, have any number of simultaneous TCP connections that each differ from all the others in at least one of those parameters. In particular, you can have any number of connections between the same two machines, with the same port on one side, and different ports on the other. This is extremely common, in fact, as web browsers often open multiple simultaneous connections to a web server to download multiple resources concurrently. All of those connections have the same server address, server port, and client address, but different client port.
If you want to have multiple simultaneous connections that are associated with one another in some way that goes beyond IP addresses, then you'll need to develop a protocol for it that involves multiple ports at at least one end. If the machines make reciprocal connections, with A connecting to B and then B connecting, separately, to A, then you'll need different ports on both sides. The port numbers to use might be fixed by the protocol or negotiated in some way, at your discretion, but the specifics described in the question are not an option.

Related

Can a server open two TCP sockets in c?

I have a server that listens for incoming connections and processes the data from a client. Then, on the same server, I want to open another TCP sockets that send the data to another server without using the set socket() option.
this a code example:
int main()
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
char server_message[50] = "Message recivied";
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(port);
int status_connect= connect(sockfd, (struct sockaddr *)
&serv_addr, sizeof(serv_addr));
if (status_connect < 0) {
printf("Error connecting to the socket \n");
exit(1);
}
listen(sockfd, 10);
int client_socket;
client_socket = accept(sockfd, NULL, NULL);
send(client_socket, server_message, sizeof(server_message), 0);
do {
char clinet_message[256];
recv(net_socket, &clinet_message, sizeof(server_resp), 0 );
sending_client_message(&clinet_message);
}while(1);
return 0;
}
I have a server that listens for incoming connections and processes
the data from a client. Then, on the same server, I want to open
another TCP sockets that send the data to another server without using
the set socket() option.
There is no specific limit on the number of unconnected, connected, and listening sockets that a system or an individual process may have open at any given time. It is routine for a system to have many, and not uncommon for individual processes to have more than one.
But you need to understand that each socket is represented by a specific file descriptor number (or even by more than one). The same file descriptor cannot refer to two different sockets at the same time. Furthermore, the same socket cannot be both connected and listening.
The socket() function is used to create a socket. From there, for a TCP socket, your options are to either
connect() it to a peer, OR
use it to listen() for and accept() connections from peers.
You cannot use the same socket for both. Instead, create separate sockets via socket() for listening and for initiating connections. Create multiple of each if you want to listen on multiple ports or connect to multiple peers.
No, you can not use a single socket for multiple connections. Not in Linux at least but it should not be possible in other OS'es as well. A file descriptor given out by socket() can not be associated with more than one connection. If you try to connect() to an already connected socket you just get EISCONN error. You need to either disconnect from the first server before connecting to another one or to get a socket() fd for every one of the TCP connections you want to have running simultaneously.

Weird IP address `0.0.0.0` being setup for the server. Not sure if it works or not

My goal is making a TCP/IP connection in a sender <-> server -> receiver fashion.
I have a server, sender and receiver. The server initial part looks like:
int main(int argc, char *argv[]){
int welcomeSocket, senderSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
if (2 != argc) {
fprintf(stderr, "Usage: %s <port>\n", argv[0]);
exit(1);
}
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
welcomeSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(atoi(argv[1]));
/* Set IP address to localhost */
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
//int len=20;
//char sbuffer[len];
//inet_ntop(AF_INET, &(serverAddr.sin_addr), sbuffer, len);
//printf("address:%s\n",sbuffer);
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Bind the address struct to the socket ----*/
bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
/*---- Listen on the socket, with 5 max connection requests queued ----*/
if(listen(welcomeSocket,5)==0)
printf("Listening\n");
else
printf("Error\n");
/*---- Accept call creates a new socket for the incoming connection ----*/
addr_size = sizeof serverStorage;
senderSocket = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
//~~~~Some more code~~~
}
however this sets up the server ip address as 0.0.0.0. I have no clue whether this is correct or not, but all until now I had manually set up the ip address as 127.0.1.1 which is what I get when I type hostname -i in the terminal.
So, currently I am having my sender connect to the same IP address, but since I am working all files in the same computer I don't know if it will work across other computers in the network with this weird ip address 0.0.0.0. Can someone clarify (and maybe help fix) this small issue to me? I have tried reading other solutions that try to explain the difference between 0.0.0.0 and 127.0.0.1 but I couldn't find anything related to the performance on the connection/communication between server and sender in a TCP/IP connection.
And then the IPv4 address is listed as 129.15.78.12 in my system settings, but then again, not sure which one should be used for the server or receiver.
The difference is that by using INADDR_ANY you bind the service to all interfaces, as explained in
http://man7.org/linux/man-pages/man7/ip.7.html
and
understanding INADDR_ANY for socket programming - c
Other than that, if you keep this config any computer trying to reach your server will connect if it uses a valid external IP address, like the one you mention you see in the system settings. Hope this clarifies your question.

Unix C socket server not accepting connections

Here's the deal, I'm writing a simple tcp socket server in C (with unix system calls) that I'm not able to get to accept connections.
From what I can tell, I get through the server initialization just fine, but when I try to connect to the port that I print out (see code below) it refuses as if nothing is there.
More to the point, when I netstat that port isn't even in use. I'm not throwing any errors with my current set up, I'm all dried up for ideas.
int main(){
int sock_fd;
int conn_fd;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
socklen_t* serlen;
socklen_t* clilen;
clilen = malloc(sizeof(socklen_t));
serlen = malloc(sizeof(socklen_t));
*serlen = sizeof(serv_addr);
*clilen = sizeof(cli_addr);
/*=============================Create Socket=============================*/
//Create Socket
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if(sock_fd<0){
fprintf(stderr,"error creating socket\n");
exit(1);}
//Initialize Server Address Struct
bzero((char *) &serv_addr, *serlen);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = 0;
/*=============================Bind Address==============================*/
//Bind socket to an address
if(bind(sock_fd,(struct sockaddr*)&serv_addr,*serlen)<0){
fprintf(stderr,"error binding\n");
exit(1);}
//Get socket data
if(getsockname(sock_fd,(struct sockaddr*)&serv_addr, serlen)<0){
fprintf(stderr,"error with socket name");
exit(1);}
/*=============================Server Started============================*/
//Listen for connections
listen(sock_fd,32);
//Print port
printf("%i", serv_addr.sin_port);
conn_fd = accept(sock_fd,(struct sockaddr*)&cli_addr,clilen);
/**Do something exciting with my new connection**/
}
Are you really trying to listen on port zero? Try a high port number, preferably > 1024. /etc/services will give a hint about free ports - but it only a set of comments, those port numbers are not enforced.
Edit: another hint. The port number should be in network order, so the assignment should use htons(). It could be that the "random numbers" you are getting are simple numbers that appear garbled because you might be on a little-endian machine (like Intel). When you print them, convert them back using ntohs().
props to #askmish for inspiring this one
//Print port
printf("%i", serv_addr.sin_port);
becomes
//Print port
printf("%i", htons(serv_addr.sin_port));
In your code:
Instead of:
serv_addr.sin_port = 0;
try this:
serv_addr.sin_port=htons(2056);//Any port no.
Instead of:
listen(sock_fd,32);
try this:
if(listen(sock_fd,SOMAXCONN)<0)//Just to be sure that you are considering max. no. of requests
{ fprintf(stderr,"error with listen");
exit(1);}
Also for:
conn_fd = accept(sock_fd,(struct sockaddr*)&cli_addr,clilen);
Add this:
if(conn_fd <0)
{
//handle the error here
}
If none of these solve your issues, then, there might be problem with the client code or your server environment.

Execute two local socket servers simultaneously in C

I'm trying to simulate a DHCP server as a university task. It's required to execute at least 2 servers (or more up to 255) since several clients will be sending messages to these servers using BROADCAST (that's where the limit of 'only' 255 servers comes from).
But when I'm trying to execute 2 servers in 2 different terminals in Ubuntu, the second server executed is rejected. I guess it's due to IP at the same localhost or whatever (I'm sorry but I don't know too much about communication protocols)
How can I run several servers on the same machine? Our teacher told us about using VMWare to run another Linux OS, and try to run both, but for me this solution is far away from my thoughts... I will post the server and client connection statements, although I don't know if there's a problem with the C statements, or the OS configuration, etc.
Server:
int sockfd, newsockfd, clilen, n;
struct sockaddr_in cli_addr, serv_addr ;
char host_name[200];
int size = sizeof(struct DHCP);
char buffer[size];
struct MACIP *macip;
if ((sockfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) {
printf("server: can't open datagram socket\n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(0);
serv_addr.sin_port = htons(SERV_UDP_PORT);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) <0) {
printf("server: can't bind local address\n");
return -1;
}
Client:
int sockfd, n, clilen;
struct sockaddr_in serv_addr, cli_addr;
char serv_host_addr[30];
int size = sizeof(struct DHCP);
char buffer[size];
printf("Dirección IP del servidor (a.b.c.d) => ");
gets(serv_host_addr);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("client: can't open datagram socket");
return -1;
}
int opt=1;
if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,&opt, sizeof(opt))<0) {
perror("Error opcion socket");
close(sockfd);
return 1;
}
bzero((char *)&cli_addr,sizeof(cli_addr));
cli_addr.sin_family = AF_INET;
if (bind(sockfd, (struct sockaddr *) &cli_addr,sizeof(cli_addr)) < 0) {
perror("client: can't bind a port");
return -1;
}
serv_addr.sin_family = AF_INET;
inet_pton(AF_INET, serv_host_addr,&serv_addr.sin_addr);
//serv_addr.sin_addr.s_addr = inet_addr(serv_host_addr);
serv_addr.sin_port = htons(SERV_UDP_PORT);
Thank you very much in advance.
Every instance of your UDP server must listen on another port. Key line in your code is this:
serv_addr.sin_port = htons(SERV_UDP_PORT);
Looks like you have the port number as a constant (SERV_UDP_PORT). To make multiple servers run at the same time you need another port for each one.
Probably best solution in your case is to have a command line argument that would define the port on which you start your server.
Each client needs to know which port (and address of course) to connect to as well. So make your client to accept similar command line argument.
To run multiple servers, they should listen on different ports on same network interface. You may get away by using two network interfaces (say wifi and ethernet) on same network with different ips.
You might try to set up alias interfaces on an existing interface. Such alias interfaces then get their own ip address each.
Using the loopback interface (lo), which typical has 127.0.0.1 assigned, such aliases to this interface could then be called lo:0, lo:1 ... and would carry the ip addresses 127.0.0.2, 127.0.0.3, ....
For details on how to achieve this see man ifconfig.

Sockets - How to find out what port and address I'm assigned

I'm having trouble figuring this out - I'm working with sockets in C using this guide - http://binarii.com/files/papers/c_sockets.txt
I'm trying to automatically get my ip and port using:
server.sin_port = 0; /* bind() will choose a random port*/
server.sin_addr.s_addr = INADDR_ANY; /* puts server's IP automatically */
...
...
bind(int fd, struct sockaddr *my_addr,int addrlen); // Bind function
After a successful bind, how do I find out what IP and Port I'm actually assigned?
If it's a server socket, you should call listen() on your socket, and then getsockname() to find the port number on which it is listening:
struct sockaddr_in sin;
socklen_t len = sizeof(sin);
if (getsockname(sock, (struct sockaddr *)&sin, &len) == -1)
perror("getsockname");
else
printf("port number %d\n", ntohs(sin.sin_port));
As for the IP address, if you use INADDR_ANY then the server socket can accept connections to any of the machine's IP addresses and the server socket itself does not have a specific IP address. For example if your machine has two IP addresses then you might get two incoming connections on this server socket, each with a different local IP address. You can use getsockname() on the socket for a specific connection (which you get from accept()) in order to find out which local IP address is being used on that connection.
The comment in your code is wrong. INADDR_ANY doesn't put server's IP automatically'. It essentially puts 0.0.0.0, for the reasons explained in mark4o's answer.

Resources