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.
Related
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
I'm learning C by writing a small application that sends a DNS query to a specified server. Here is an example of the network code:
int send_query()
{
int sockfd;
struct sockaddr_in server;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("cannot create socket\n");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(53);
inet_pton(AF_INET, "8.8.8.8", &(server.sin_addr));
sendto(sockfd, const void *buffer, size_t length, 0, (struct sockaddr *) &server, sizeof(server));
}
This works fine as the query is succesfully sent, and a reply is recieved. However, by sniffing the traffic with Wireshark I can see the message: Destination unreachable (Port unreachable).
I found out that I can avoid this by calling bind() before sendto():
int send_query()
{
int sockfd;
struct sockaddr_in server;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("cannot create socket\n");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(53);
inet_pton(AF_INET, "8.8.8.8", &(server.sin_addr));
if(bind(sockfd, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind failed\n");
}
sendto(sockfd, const void *buffer, size_t length, 0, (struct sockaddr *) &server, sizeof(server));
}
Now the Destination unreachable (Port unreachable) message is gone, but the application has to be run with root privileges as it will bind to port 53.
Is it possible to modify the code so a random non-privileged source port is used instead?
Problem solved
The problem occured because of a stupid mistake. I had simply commented out recvfrom(). As I was sniffing the traffic while testing the application, I could see the response and error arrving at my computer, and mistakenly confused this as the application was receving. Because I don't know what the hell I'm doing, I started to mess around with bind() etc. and this avalanche of failure started.
For brevity I did not post all the code, but the issue had probably been solved instantly if had did that instead.
You can bind to port 0 to let the OS randomly pick one available for you (just like INADDR_ANY is 0). See https://stackoverflow.com/a/1077305/3543692
Also, binding to port 53 makes no sense. The 53 port is the port of the DNS server, not the DNS client. Think if all the DNS clients on your computer use 53 for DNS client port, then only one DNS request to a server can be proceeded concurrently. Typically, all clients (both TCP/UDP) use random unused ports assigned by OS.
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.
I would like to ask about the getpeername() function since it returns data as the title states. I tried to get value directly from accept() function, and the result also happens the same. Value of port seems to appear randomly even though value of address is correct(address is 127.0.0.1 since I run multi-processes on an only machine). The return code of getpeername() is 0 (status = 0). I'm using gcc version 4.8.1. I write a peer 2 peer chat application without server. The following is my code:
struct sockaddr_in addr;
socklen_t addr_len;
int tempPort, serverSockfd;
char test[100];
// Get serverSockfd successfully....
serverSockFd = initializeSock(PORT) // In this function I initialize socket(), bind() and listen(), serverSockFd is returned by the value of socket()
addr_len = sizeof addr;
newSock = accept(serverSockfd, (struct sockaddr *)&addr, &addr_len);
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
addr_len = sizeof addr;
if ((status = getpeername(newSock, (struct sockaddr *) &addr, &addr_len)) != 0){
printf("getpeername() error!\n");
}
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
Thanks very much for any your comment. Here is a partial code in initializeSock():
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("SocketInit(): socket() error!\n");
exit(1);
}
ret_val = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
if(ret_val == -1)
{
perror("SocketInit(): setsockopt(SO_REUSEADDR) error!\n");
exit(1);
}
gethostname(hostname,100);
host_entry = gethostbyname(hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
ret_val = bind(sd, (struct sockaddr*) &addr, sizeof(addr));
if(ret_val == -1)
{
perror("SocketInit(): bind() error!\n");
printf("For port:%d\n",port);
exit(1);
}
....
return sd;
This is the code to connect to server part of a peer. ConnectSock(portOfPeerA):
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("ConnectToServer(): socket() error!\n");
exit(1);
}
if (port != 0) {
addr.sin_family = AF_INET;
addr.sin_port = htons(portOfPeerA);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
// Do I need to bind() the port of peer B when it would like to connect to peer A?
ret_val = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
if(ret_val == -1)
{
printf("Error connect());
exit(1);
}
...
I don't know which port you accept from the peer, but if the peer is connecting to your server (e.g. then one calling accept) it will connect from a (more or less) random port, that's how TCP works. It connects from a fixed port only if the peer explicitly binds to that port before connecting.
This means, that the peers originating port is not defined on the server side (where your code fragments are from) but on the client side (the side which calls connect and where you only do connect but no bind).
But, please note that it might give problems with repeated connections, if both client and server use fixed IP and ports, because then you will get the same 4-tupel in TCP which defines the connections for repeated connections and thus go into all this trouble with the various TIME_WAIT states. So it is better to let the client just pick an available port and not force it to use a specific one.
getpeername() (and accept()) reports the IP and port that the remote party is locally bound to on its end. If the remote party is a client that did not call bind() before calling connect() then connect() performs an implicit bind to a random available port. That is what you are seeing, and that it typical usage. Most clients do not need to call bind() before connect(), but there are use cases where doing so is necessary, so don't rule it out.
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. :)