Can a server open two TCP sockets in c? - 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.

Related

How to connect a TCP server to another TCP server

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.

socket connect() vs bind()

Both connect() and bind() system calls 'associate' the socket file descriptor to an address (typically an ip/port combination). Their prototypes are like:-
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
and
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
What is the exact difference between 2 calls? When should one use connect() and when bind()?
Specifically, in some sample server client codes, found that client is using connect() and server is using the bind() call. Reason was not fully clear to me.
To make understanding better , lets find out where exactly bind and connect comes into picture,
Further to positioning of two calls , as clarified by Sourav,
bind() associates the socket with its local address [that's why server side binds, so that clients can use that address to connect to server.]
connect() is used to connect to a remote [server] address, that's why is client side, connect [read as: connect to server] is used.
We cannot use them interchangeably (even when we have client/server on same machine) because of specific roles and corresponding implementation.
I will further recommend to correlate these calls TCP/IP handshake .
So, who will send SYN here, it will be connect(). While bind() is used for defining the communication end point.
The one liner : bind() to own address, connect() to remote address.
Quoting from the man page of bind()
bind() assigns the address specified by addr to the socket referred to by the file descriptor sockfd. addrlen specifies the size, in bytes, of the address structure pointed to by addr. Traditionally, this operation is called "assigning a name to a socket".
and, from the same for connect()
The connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr.
To clarify,
bind() associates the socket with its local address [that's why
server side binds, so that clients can use that address to connect
to server.]
connect() is used to connect to a remote [server] address, that's
why is client side, connect [read as: connect to server] is used.
I think it would help your comprehension if you think of connect() and listen() as counterparts, rather than connect() and bind(). The reason for this is that you can call or omit bind() before either, although it's rarely a good idea to call it before connect(), or not to call it before listen().
If it helps to think in terms of servers and clients, it is listen() which is the hallmark of the former, and connect() the latter. bind() can be found - or not found - on either.
If we assume our server and client are on different machines, it becomes easier to understand the various functions.
bind() acts locally, which is to say it binds the end of the connection on the machine on which it is called, to the requested address and assigns the requested port to you. It does that irrespective of whether that machine will be a client or a server. connect() initiates a connection to a server, which is to say it connects to the requested address and port on the server, from a client. That server will almost certainly have called bind() prior to listen(), in order for you to be able to know on which address and port to connect to it with using connect().
If you don't call bind(), a port and address will be implicitly assigned and bound on the local machine for you when you call either connect() (client) or listen() (server). However, that's a side effect of both, not their purpose. A port assigned in this manner is ephemeral.
An important point here is that the client does not need to be bound, because clients connect to servers, and so the server will know the address and port of the client even though you are using an ephemeral port, rather than binding to something specific. On the other hand, although the server could call listen() without calling bind(), in that scenario they would need to discover their assigned ephemeral port, and communicate that to any client that it wants to connect to it.
I assume as you mention connect() you're interested in TCP, but this also carries over to UDP, where not calling bind() before the first sendto() (UDP is connection-less) also causes a port and address to be implicitly assigned and bound. One function you cannot call without binding is recvfrom(), which will return an error, because without an assigned port and bound address, there is nothing to receive from (or too much, depending on how you interpret the absence of a binding).
bind tells the running process to claim a port. i.e, it should bind itself to port 80 and listen for incomming requests. with bind, your process becomes a server. when you use connect, you tell your process to connect to a port that is ALREADY in use. your process becomes a client. the difference is important: bind wants a port that is not in use (so that it can claim it and become a server), and connect wants a port that is already in use (so it can connect to it and talk to the server)
From Wikipedia http://en.wikipedia.org/wiki/Berkeley_sockets#bind.28.29
connect():
The connect() system call connects a socket, identified by its file descriptor, to a remote host specified by that host's address in the argument list.
Certain types of sockets are connectionless, most commonly user datagram protocol sockets. For these sockets, connect takes on a special meaning: the default target for sending and receiving data gets set to the given address, allowing the use of functions such as send() and recv() on connectionless sockets.
connect() returns an integer representing the error code: 0 represents success, while -1 represents an error.
bind():
bind() assigns a socket to an address. When a socket is created using socket(), it is only given a protocol family, but not assigned an address. This association with an address must be performed with the bind() system call before the socket can accept connections to other hosts. bind() takes three arguments:
sockfd, a descriptor representing the socket to perform the bind on.
my_addr, a pointer to a sockaddr structure representing the address to bind to.
addrlen, a socklen_t field specifying the size of the sockaddr structure.
Bind() returns 0 on success and -1 if an error occurs.
Examples:
1.)Using Connect
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(){
int clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
socklen_t addr_size;
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
/*---- 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(7891);
/* Set the IP address to desired host to connect to */
serverAddr.sin_addr.s_addr = inet_addr("192.168.1.17");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Connect the socket to the server using the address struct ----*/
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
/*---- Read the message from the server into the buffer ----*/
recv(clientSocket, buffer, 1024, 0);
/*---- Print the received message ----*/
printf("Data received: %s",buffer);
return 0;
}
2.)Bind Example:
int main()
{
struct sockaddr_in source, destination = {}; //two sockets declared as previously
int sock = 0;
int datalen = 0;
int pkt = 0;
uint8_t *send_buffer, *recv_buffer;
struct sockaddr_storage fromAddr; // same as the previous entity struct sockaddr_storage serverStorage;
unsigned int addrlen; //in the previous example socklen_t addr_size;
struct timeval tv;
tv.tv_sec = 3; /* 3 Seconds Time-out */
tv.tv_usec = 0;
/* creating the socket */
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
printf("Failed to create socket\n");
/*set the socket options*/
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
/*Inititalize source to zero*/
memset(&source, 0, sizeof(source)); //source is an instance of sockaddr_in. Initialization to zero
/*Inititalize destinaton to zero*/
memset(&destination, 0, sizeof(destination));
/*---- Configure settings of the source address struct, WHERE THE PACKET IS COMING FROM ----*/
/* Address family = Internet */
source.sin_family = AF_INET;
/* Set IP address to localhost */
source.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY = 0.0.0.0
/* Set port number, using htons function to use proper byte order */
source.sin_port = htons(7005);
/* Set all bits of the padding field to 0 */
memset(source.sin_zero, '\0', sizeof source.sin_zero); //optional
/*bind socket to the source WHERE THE PACKET IS COMING FROM*/
if (bind(sock, (struct sockaddr *) &source, sizeof(source)) < 0)
printf("Failed to bind socket");
/* setting the destination, i.e our OWN IP ADDRESS AND PORT */
destination.sin_family = AF_INET;
destination.sin_addr.s_addr = inet_addr("127.0.0.1");
destination.sin_port = htons(7005);
//Creating a Buffer;
send_buffer=(uint8_t *) malloc(350);
recv_buffer=(uint8_t *) malloc(250);
addrlen=sizeof(fromAddr);
memset((void *) recv_buffer, 0, 250);
memset((void *) send_buffer, 0, 350);
sendto(sock, send_buffer, 20, 0,(struct sockaddr *) &destination, sizeof(destination));
pkt=recvfrom(sock, recv_buffer, 98,0,(struct sockaddr *)&destination, &addrlen);
if(pkt > 0)
printf("%u bytes received\n", pkt);
}
I hope that clarifies the difference
Please note that the socket type that you declare will depend on what you require, this is extremely important
Too Long; Don't Read: The difference is whether the source (local) or the destination address/port is being set. In short, bind() set the source and connect() set the destination. Regardless of TCP or UDP.
bind()
bind() set the socket's local (source) address. This is the address where packets are received. Packets sent by the socket carry this as the source address, so the other host will know where to send back its packets.
If receive is not needed the socket source address is useless. Protocols like TCP require receiving enabled in order to send properly, as the destination host send back a confirmation when one or more packets have arrived (i.e. acknowledgement).
connect()
TCP has a "connected" state. connect() triggers the TCP code to try to establish a connection to the other side.
UDP has no "connected" state. connect() only set a default address to where packets are sent when no address is specified. When connect() is not used, sendto() or sendmsg() must be used containing the destination address.
When connect() or a send function is called, and no address is bound, Linux automatically bind the socket to a random port. For technical details, take a look at inet_autobind() in Linux kernel source code.
Side notes
listen() is TCP only.
In AF_INET family, the socket's source or destination address (struct sockaddr_in) is composed by an IP address (see IP header), and TCP or UDP port (see TCP and UDP header).

C UNIX - How to use multiple sockets server-side to receive UDP messages in order to filter them?

I am writing UDP server and client in C on UNIX. I need to handle each client in its own thread on server. In each thread, I want to receive only messages from corresponding client. Right now I am peeking messages using recvfrom and checking message whether it is "mine".
I heard that it is possible to have multiple sockets listening on the same host:port and connect each of them to corresponding client so it will receive messages only from the said client. Here is the code I run when I run into new client. However, after first client connects messages are in fact filtered, but not only on new socket, but also on main socket listening for new clients, so I cant connect new clients.
void fun(int* sockfd, struct sockaddr_in* my_addr, struct sockaddr_in* cli_addr)){
if ((*sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
ERR("socket");
}
int optval = 1;
bzero(my_addr, sizeof (*my_addr));
my_addr->sin_family = AF_INET;
my_addr->sin_port = htons(PORT);
my_addr->sin_addr.s_addr = htonl(INADDR_ANY);
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)) < 0) {
ERR("setsockopt");
}
if (bind(sockfd, (struct sockaddr*) my_addr, sizeof (*my_addr)) == -1) {
ERR("bind");
}
if (connect(*socket, (struct sockaddr*) cli_addr, sizeof (*cli_addr)) < 0)
ERR("connect");
}
}
Is there a better (and working) way to filter UDP messages?
In my opinion you should use one thread for receiving and sending data and then dispatch to the other threads.
There is no need for more than one socket server side. One socket receive all datagrams, you process them by extracting the source, and then dispatch it.
You could do something like this:
Datagram is read:
source is known, call the backback you have for it
source is not known, create a new thread, and register a callback for this source.
Whenever you want to "disconnect" a client, unregister the callback and remove the thread.
Note that by "disconnect" I mean in a logical way for your application, since UDP socket are not connected.

When binding a client TCP socket to a specific local port with Winsock, SO_REUSEADDR does not have any effect

I'm binding a client TCP socket to a specific local port. To handle the situation where the socket remains in TIME_WAIT state for some time, I use setsockopt() with SO_REUSEADDR on a socket.
It works on Linux, but does not work on Windows, I get WSAEADDRINUSE on connect() call when the previous connection is still in TIME_WAIT.
MSDN is not exactly clear what should happen with client sockets:
[...] For server applications that need to bind multiple sockets to the same port number, consider using setsockopt (SO_REUSEADDR). Client applications usually need not call bind at all—connect chooses an unused port automatically. [...]
How do I avoid this?
When you create a socket with socket(), it has only a type and a protocol family. The ideal is to bind() it to a local address:port too.
The error you mentioned normally happens when the last connection to the same host:port didn't have a graceful shutdown (FIN/ACK FIN/ACK). In these cases, the socket stays in TIME_WAIT state for a certain period of time (OS dependent, but adjustable).
What happens then is when you try to connect() to the same host and same port, it uses the default socket's name/address/port/etc, but this combination is already in use by your zombie socket. To avoid this, you can change the local address:port used to establish the connection by calling bind() after the socket creation, providing the sockaddr struct filled with your local address and a random port.
int main() {
int ret, fd;
struct sockaddr_in sa_dst;
struct sockaddr_in sa_loc;
char buffer[1024] = "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
fd = socket(AF_INET, SOCK_STREAM, 0);
// Local
memset(&sa_loc, 0, sizeof(struct sockaddr_in));
sa_loc.sin_family = AF_INET;
sa_loc.sin_port = htons(LOCAL_RANDOM_PORT);
sa_loc.sin_addr.s_addr = inet_addr(LOCAL_IP_ADDRESS);
ret = bind(fd, (struct sockaddr *)&sa_loc, sizeof(struct sockaddr));
assert(ret != -1);
// Remote
memset(&sa_dst, 0, sizeof(struct sockaddr_in));
sa_dst.sin_family = AF_INET;
sa_dst.sin_port = htons(80);
sa_dst.sin_addr.s_addr = inet_addr("64.233.163.104"); // google :)
ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr));
assert(ret != -1);
send(fd, buffer, strlen(buffer), 0);
recv(fd, buffer, sizeof(buffer), 0);
printf("%s\r\n", buffer);
}
UPDATE: As using a specific local port is a requirement, consider setting SO_LINGER with l_onoff=1 and l_linger=0 so your socket won't block upon close/closesocket, it will just ignore queued data and (hopefully) close the fd. As a last resort you can adjust the TIME_WAIT delay by changing the value of this registry key (highly discouraged!):
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay
You don't specify which Windows platform you're running on, that may affect things as may the security principal that you're running under (i.e. are you admin?)...
This may help: http://blogs.msdn.com/wndp/archive/2005/08/03/Anthony-Jones.aspx
Be careful in binding the local port NOT to use the loopback address "127.0.0.1", or you will get connection timeouts. Better not to populate the sa_loc.sin_addr.s_addr at all - that works just fine.

UDP Sockets in C

I'm working on a homework problem for class. I want to start a UDP Server that listens for a file request. It opens the file and sends it back to the requesting client with UDP.
Heres the server code.
// Create UDP Socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Can't create socket");
exit(-1);
}
// Configure socket
memset(&server, 0, sizeof server);
server.sin_family = AF_INET; // Use IPv4
server.sin_addr.s_addr = htonl(INADDR_ANY); // My IP
server.sin_port = htons(atoi(argv[1])); // Server Port
// Bind socket
if ((bind(sockfd, (struct sockaddr *) &server, sizeof(server))) == -1) {
close(sockfd);
perror("Can't bind");
}
printf("listener: waiting to recvfrom...\n");
if (listen(sockfd, 5) == -1) {
perror("Can't listen for connections");
exit(-1);
}
while (1) {
client_len = sizeof(struct sockaddr_in);
newsockfd = accept(sockfd, (struct sockaddr*)&client,&client_len);
if (newsockfd < 0) {
perror("ERROR on accept");
}
// Some how parse request
// I do I use recv or recvfrom?
// I do I make new UDP socket to send data back to client?
sendFile(newsockfd, filename);
close(newsockfd);
}
close(sockfd);
I'm kind of lost how do I recv data from the client? And how to I make a new UDP connection back to the client?
How UDP is different from TCP:
message-oriented, not stream-oriented. You don't read/write or send/recv. You sendto/recvfrom. The size of message is limited to 64K. Each call to recvfrom gets one message sent by a call to sendto. If recvfrom passes a buffer that's smaller than the size of message, the rest of message is gone for good.
no connections. Therefore no listen/accept/connect. You send a message to a particular address/port. When you receive message (on the address/port to which your socket is bound), you get the source of the incoming message as an output parameter to recvfrom.
no guarantees. The messages can be dropped or received out of order. If I remember correctly, they cannot be truncated, though.
One last word of caution - you may find yourself re-inventing TCP over UDP. In that case, stop and go back to TCP.
I have written a UDP server-client in C , where the client sends a registration number and the server gives a name as the feedback.
SERVER
0. Variable initialization
1. sock()
2. bind()
3. recvfrom()
4. sendto()
CLIENT
0. gethostbyname()
1. sock()
2. bzero()
4. sendto()
5. recvfrom()
Hope it helps. You can find the example code here udp server/client
accept is only used for connection oriented (STREAM) sockets. UDP is not stream, oriented, so there are no connections and you can't use accept(2) -- it will return EOPNOTSUPP.
Instead, you just read packets directly from the bound service socket (generally using recvfrom(2) so you can tell where thy came from, though you can use recv or just read if you don't care), afterwhich you can send packets back using the same socket (and generally using sendto(2))
Keep in mind that UDP is connectionless. It only sends packets, and is not suitable for sending files - unless the entire content fit in one UDP packet.
If you anyway want to send/receive UDP packets, you simply call sendto/recvfrom with the appropriate addresses.

Resources