C Server connect to Client - c

I'm trying to make a Server/Client with push notifications.
First of all the Client connects with Server and then Server saves IP address and port of the client. At some point server needs to connect with client to send a notification.
This is how Server saves Client IP address and port after the accept of the first connection:
char client_ip[INET_ADDRSTRLEN];
int port_c;
// Socket, ..., bind, listen, accept
// Gets Client IP address
struct sockaddr_in* pV4Addr = (struct sockaddr_in*)&cli_addr;
struct in_addr ipAddr = pV4Addr->sin_addr;
inet_ntop( AF_INET, &ipAddr, client_ip, INET_ADDRSTRLEN );
printf("Client ip: %s\n", client_ip);
// Gets Client Port Number
port_c = (int) ntohs(cli_addr.sin_port);
printf("Client port is: %d\n", (int) ntohs(cli_addr.sin_port));
// [ ... ]
// Time to send notification to client
bzero((char *) &cli_addr, sizeof(cli_addr));
// Setting IP address and port
cli_addr.sin_family = AF_INET;
bcopy(client_ip, (char *)&cli_addr.sin_addr.s_addr, strlen(client_ip));
cli_addr.sin_port = htons(port_c);
// Create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// Bind socket to the local address
if(bind(sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0)
error("Error bind");
if (connect(sockfd, (struct sockaddr *)&cli_addr, sizeof(cli_addr)) < 0)
error("ERROR connecting");
I get bind error: Can't assign requested address.
And I am not sure how to code Client after the first connection. It would be listening and accepting the connection but if I do in the Client's code
cli_addr.sin_family = AF_INET;
cli_addr.sin_addr.s_addr = INADDR_ANY;
cli_addr.sin_port = htons(port_client);
Will the IP address be the same as the first connection?
If someone has another solution or better, please share it.

You are trying to bind the server socket to a client IP. That cannot work. You can only bind a socket to a local address. You must use bind for incomming connections, not for outgoing ones.
If you want your server to respond to a request from the client, simply use the socket returned by accept(), then send() using this socket.
You server code should look like this:
SOCKET sock_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sock_local_addr;
memset(&sock_local_addr, 0, sizeof(sock_local_addr));
sock_local_addr.sin_family = AF_INET;
sock_local_addr.sin_port = htons(SERVER_PORT);
sock_local_addr.sin_addr.s_addr = INADDR_ANY;
bind(sock_server, (const struct sockaddr *)&sock_local_addr, sizeof(sock_local_addr)); // bind server socket to any network interface of the server
listen(sock_server, 10);
struct sockaddr_in client_addr;
SOCKLEN_T client_addr_size = sizeof(client_addr);
SOCKET sock_client = accept(sock_server, (struct sockaddr *)&client_addr, &client_addr_size); // accept incomming connection; this will block until a client connects
recv_size = recv(sock_client, buf_in, sizeof(buf_in), 0); // receive data from client
send(sock_client, buf_out, sizeof(buf_out), 0); // send data back to client (buf_out is buffer containing the data to be sent)
shutdown(sock_client, SHUT_RDWR); // shutdown connection with client

Related

Invalid argument to connect()

I'm trying to write code to setup a client socket that can send/receive messages from a server. Here's what I have:
// Create the socket
int s = socket(AF_INET, SOCK_STREAM, 0); // TODO: error checking
// Setup the client and server addresses
struct sockaddr_in cli_addr;
memset(&cli_addr, 0, sizeof(cli_addr));
cli_addr.sin_family = AF_INET;
cli_addr.sin_port = htons(7654);
cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(11111);
serv_addr.sin_addr.s_addr = inet_addr("XXX.XXX.XXX.XXX");
// Bind the socket to the client address (so we can receive messsages)
if (bind(s, (struct sockaddr*)&cli_addr, sizeof(cli_addr)) == -1) {
perror("bind failed");
exit(errno);
}
// Connect the socket to the server address (so we can send messages)
if (connect(s, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
perror("connect failed");
exit(errno);
}
When I run this, I'm getting the error connect failed: Invalid argument. I don't see what I'm doing incorrectly here, though.
cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
...
serv_addr.sin_addr.s_addr = inet_addr("XXX.XXX.XXX.XXX");
You'll bind the socket to localhost (127.0.0.1) but then you connect to an address which likely is not localhost. There is no way such a TCP with a fully internal IP address (i.e. not accessible from outside the machine) to an IP address of a different system can be created, hence "Invalid argument".
It is unclear what you are trying to achieve with the bind in the first place so it might be the best to just remove it. In this case it will automatically pick a local IP and port which can be used in a connection to the given destination IP.

Binding a port for client tcp socket

I have a problem about 'binging a local port for a client tcp socket'.
The code is as below:
void tcpv4_cli_connect(const char *srvhost, in_port_t srvport,
const char *clihost, in_port_t cliport)
{
struct sockaddr_in srvaddr, cliaddr;
struct in_addr inaddr;
int sockfd;
bzero(&srvaddr, sizeof(srvaddr));
inet_aton(srvhost, &inaddr);
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr = inaddr;
srvaddr.sin_port = htons(srvport);
bzero(&cliaddr, sizeof(cliaddr));
inet_aton(clihost, &inaddr);
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr = inaddr;
cliaddr.sin_port = htons(cliport);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bind(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr));
if (connect(sockfd, (struct sockaddr *) &srvaddr, sizeof(srvaddr)) != 0)
perror("Something Wrong");
return;
}
int main(int argc, char *argv[])
{
// Wrong for "220.181.111.86", but ok for "127.0.0.1"
tcpv4_cli_connect("220.181.111.86", 80, "127.0.0.1", 40888);
return 0;
}
When I do tcpv4_cli_connect("220.181.111.86", 80, "127.0.0.1", 40888) in main function, (220.181.111.86 is an address on Internet), an error will show up: Something Wrong: Invalid argument.
And if I comment bind(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) in the code, things will be fine and a random port is used for client socket.
But it is alright when I do tcpv4_cli_connect("127.0.0.1", 80, "127.0.0.1", 40888) whether or not binding a port to client socket.
What does Invalid argument mean for a connect operation? I wonder if it is only allowed to bind a specific port for the client to connect to local address? Clients can only use random port to connect to a external server?
Is there someting I misunderstood?
/br
Ruan
When you bind() to 127.0.0.1 (INADDR_LOOPBACK), you are binding to a loopback interface that does not have access to the outside world, only to itself, so you cannot connect() to any IP other than 127.0.0.1. If you want to bind() to a local interface when you connect() to an outside server, you have to bind to the actual IP of an interface that is connected to a network that can reach that server.
If all you want to do is bind() to a specific port, but allow the OS to pick an appropriate interface for you, then bind to 0.0.0.0 (INADDR_ANY) instead.

Cannot send information between multiple clients connected to a server

I have multiple clients connected to a server. Each time the server sends a string which contains the IP and address of client 1 to client 2, client 2 connects to client 1 and sends it a message.
Server and clients are local; they have same IP but different listening ports.
I get the following error: Transport endpoint is already connected.
After debugging, I think it is because of the same IP address, although i don't understand why it doesn't connect through the port. Client 2 gets the correct port of client 1.
(note: i omitted the error handling)
Here's the code:
sockfd = socket(AF_INET, SOCK_STREAM,0); //the one for the server
sockfd2 = socket(AF_INET, SOCK_STREAM,0); //the one for the client
//creating client
client.sin_family = AF_INET;
client.sin_port = htons(atoi(argv[3])); // the port is read from command line
client.sin_addr.s_addr = INADDR_ANY;
//bind
int b = bind(sockfd2, (struct sockaddr *) &client, sizeof(struct sockaddr));
//listen
listen(sockfd2,1); //only 1 client can connect to this one!
//creating server
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(atoi(argv[5])); // the port is read from command line
inet_aton(argv[4], &serv_addr.sin_addr);
connect(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr));
while(1){
... // the client connects to the server and gets the string
destination.sin_family = AF_INET;
destination.sin_addr.s_addr= inet_addr(address);
destination.sin_port = htons(atoi(port));
//this line gives the error
if(connect(sockfd2,(struct sockaddr*)&destination, sizeof(destination)<0)
error("Error connecting");
//the sending
n = send(sockfd2, message, strlen(message), 0);
if(n<0)
error("Error sending");
....
}
sockfd2 which you try to connect() is already bound, and assigned a role (by means of listen) to be a server socket. Basically the only valid operation it can do is to accept() an incoming connection.

UDP Client shows 'UDP Connected' while no UDP Server running on localhost

What is wrong with the following function ??
It should throw an error as I have no UDP server running on localhost.
int openUdpSocket(int port) {
int sock,sin_size;
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
struct hostent *host;
host= (struct hostent *) gethostbyname((char *)"127.0.0.1");
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(server_addr.sin_zero),8);
sin_size = sizeof(struct sockaddr);
Now the Following part causing trouble : -
int error = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(error < 0){
printf("Connection error\n");
exit(-1);
}
if (verbose)
printf("UDP connected\n");
return sock;
}
Output:
udit#mylaptop:~/Desktop/benchmark$ ./a.out
UDP connected
Note that I have created a similar function for TCP and the same thing is working fine with TCP that means when no TCP Server running it shows connection error and when TCP Server running then TCP Connected
The UDP Client mentioned above needs to receive response in form of some status codes in future. SO, Do I need to use bind() function here ??
You need to lookup what connect() does for a SOCK_DGRAM socket. It doesn't imply the existence of a peer. It only establishes an inbound and outbound IP address filter. See man 2 connect.
for UDP communication you need to use Sendto and Receivefrom functions,
bind and connect are not required for UDP communication.
try to search about this two functions and use them. :)

UDP Client Source port in C?

I am writing a UDP client and I need to mention the source port of my UDP packet in my data to send.
How my program can get the random port number generated by kernal which udp client is using to send data to voip server.
so
How can i specify a specific UDP source port before sending data.
I will be very very thankful. Please reply me as soon as possible. My project is stopped at this point.
Use bind to bind your socket to port 0, which will allow you to use getsockname to get the port. you can also bind your socket to a specific port, if you wish.
eg (assuming IPv4 socket, no error checking):
struct sockaddr_in sin = {};
socklen_t slen;
int sock;
short unsigned int port;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = 0;
bind(sock, (struct sockaddr *)&sin, sizeof(sin));
/* Now bound, get the address */
slen = sizeof(sin);
getsockname(sock, (struct sockaddr *)&sin, &slen);
port = ntohs(sin.sin_port);
Alternately, if you are communicating with a single server, you can use connect on your UDP socket (which also gives you the handy side effect of allowing you to use send instead of sendto, and making the UDP socket only accept datagrams from your "connected" peer), then use getsockname to obtain your local port/address. You may still choose to bind your socket prior to using connect.
eg:
struct sockaddr_in sin = {};
socklen_t slen;
int sock;
short unsigned int port;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
/* set sin to your target host... */
...
connect(sock, (struct sockaddr *)&sin, sizeof(sin));
/* now retrieve the address as before */
slen = sizeof(sin);
getsockname(sock, (struct sockaddr *)&sin, &slen);
port = ntohs(sin.sin_port);
You should bind(2) your socket to a port of your choosing. See also
man 7 ip and man 7 udp.

Resources