I study sockets and try to write a very simple application. The client sends the string "Hello there!", the server accepts it, displays at itself and sends back. Wrote the client (Linux Ubuntu 18.04), and the server (macOS 10.14.2, IP: 217.144.173.149):
server:
int main()
{
int sock, listener;
struct sockaddr_in addr;
char buf[1024];
int bytes_read;
listener = socket(AF_INET, SOCK_STREAM, 0);
if(listener < 0)
{
perror("socket");
exit(1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(3425);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
exit(2);
}
listen(listener, 1);
while(1)
{
sock = accept(listener, 0, 0);
if(sock < 0)
{
perror("accept");
exit(3);
}
while(1)
{
bytes_read = recv(sock, buf, 1024, 0);
if (bytes_read <= 0) break;
printf(buf);
send(sock, buf, bytes_read, 0);
}
close(sock);
}
return 0;
}
client:
int main()
{
char message[] = "Hello there!\n";
char buf[sizeof(message)];
int sock;
struct sockaddr_in addr;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
perror("socket");
exit(1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(3425);
addr.sin_addr.s_addr = inet_addr("217.144.173.149");
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("connect");
exit(2);
}
send(sock, message, sizeof(message), 0);
recv(sock, buf, sizeof(message), 0);
printf(buf);
close(sock);
return 0;
}
However, after starting the client, it just hangs and after a while gives an error: connect: Connection timed out. The server at the same time, of course, works. Google search gave no results (maybe I was looking for). What I did wrong?
The problem is in the way you are converting the IP address from presentation type to network type.
You should use the IP address if it is static instead of INADDR_ANY.
If the problem stays try using a different function to convert the IP.
For further reference go here.
As other answers suggested , please check if your server is listening on properly using netstat command in server
From the server , check if firewalld or anyfirewall specific software is running
Try using different port to bind on server , may be 8080 or something else .
I also suggest you to read the excellent guide (beejs network programming guide)
https://beej.us/guide/bgnet/
Check server's ipfw IP Firewall. (Open port 3425 , which is the server port listen on)
Server's IP address must be public IP. Or the server and client in the same local area network.
If you just want to test your code. You can run server and client in the same computer. Open two terminal and the one run server , the other run client. And client change the connect ip 217.144.173.149 to 127.0.0.1
127.0.0.1 mean localhost.
Related
I have a Linux C application that must use UDP. The server broadcasts a "discovery packet" and then listens for any connected clients to answer with a similar echo. By using ports, the clients and server can then communicate using their different ports.
Here is how the server broadcasts its discovery packet:
int main() {
puts("starting");
int sock;
int yes = 1;
struct sockaddr_in broadcast_addr;
int addr_len;
int count;
int ret;
fd_set readfd;
char buffer[1024];
char outbound_buffer[63];
int i;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("sock error");
return -1;
}
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes));
if (ret == -1) {
perror("setsockopt error");
return 0;
}
memset(outbound_buffer,0,sizeof(outbound_buffer));
addr_len = sizeof(struct sockaddr_in);
memset((void*)&broadcast_addr, 0, addr_len);
broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
broadcast_addr.sin_port = htons(PORT);
outbound_buffer[0] = 0xEF;
outbound_buffer[1] = 0xFE;
outbound_buffer[2] = 0x02;
ret = sendto(sock, outbound_buffer, 63, 0, (struct sockaddr*) &broadcast_addr, addr_len);
This works fine; the client receives the discovery and gets the server's IP and port:
int main() {
stoplink = 0;
stopData = 0;
int addr_len;
int count;
int ret;
fd_set readfd;
char buffer[1024];
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("sock error\n");
return -1;
}
addr_len = sizeof(struct sockaddr_in);
memset((void*)&server_addr, 0, addr_len);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(PORT);
ret = bind(sock, (struct sockaddr*)&server_addr, addr_len);
if (ret < 0) {
perror("bind error\n");
return -1;
}
while (1) {
puts("Initialized; await discovery");
FD_ZERO(&readfd);
FD_SET(sock, &readfd);
ret = select(sock+1, &readfd, NULL, NULL, 0);
if (ret > 0) {
if (FD_ISSET(sock, &readfd)) {
count = recvfrom(sock, buffer, 1024, 0, (struct sockaddr*)&client_addr, &addr_len);
if((buffer[0] & 0xFF) == 0xEF && (buffer[1] & 0xFF) == 0xFE) {
fprintf(stderr,"discovery packet detected\n");
cmdport = ntohs(client_addr.sin_port);
printf("\nClient connection information:\n\t IP: %s, Port: %d\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
count = sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&client_addr,
sizeof(client_addr));
}
}
}
puts("Now starting command processing loop");
This also works fine... but it sends the reply to the port on the server from which the broadcast came - this was randomly selected automatically by the server; so how do I know what port to listen to on the server side to receive the client's reply?
The server doesn't need to do anything additional. Once it sends a packet, the port on the server side is set.
For example, if the client sees that the server message came from port 34567, then the server socket is using port 34567. Then any messages sent to the server at port 34567 can be read by the same server socket.
So the server can just call recvfrom and it will get the response from the client.
You've swapped the normal meanings of the words "client" and "server" -- normally the server will bind to a specific port and listen for (broadcast) packets, while the client will broadcast a discovery packet to find the server. When the server receives a broadcast, it will reply to the client, which will just do a recv on it's (single) socket to get the reply, which will have the server's IP address. If there might be multiple servers, then they'll all reply to the client, so the client will see multiple replies and need to choose from them. But, most importantly, the client never needs to actually know which port it is using -- it just lets the system choose an otherwise unused port for it.
Thanks for all the input. getsockname() is what I needed.
I am currently coding a small chat application in C for learning network.
I develop using the Transmission Control Protocol with socket in C. I was able to connect to my server with a client not coded by myself (on local network). Now telnet succeed to connect to my chat server(so with server and telnet client on the same computer) and I can send and receive message BUT my very simple client cannot connect to it.
Since the begining I use port 9002 and right now I am trying to connect with IPv6 address ::1.
Here the "accept client" code of my server:
int main(void)
{
//Create the socket
int sock = socket(AF_INET6, SOCK_STREAM, 0);
printf("Socket créer\n");
//Set up the socket interface
struct sockaddr_in6 sin6 = { 0 };
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(PORT);
sin6.sin6_addr = in6addr_any;
//Bind the socket on the port
if(bind(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr_in6)) == SO_ERROR)
{
perror("bind()");
errx(EXIT_FAILURE, "Fail to bind");
}
//Make the sockey listen the port
if(listen(sock, MAX_CLIENT) == SO_ERROR)
{
perror("listen()");
errx(EXIT_FAILURE, "Fail to listen");
}
printf("Socket listening\n");
int csock;
size_t clientID = 0;
--snip--
while(1)
{
struct sockaddr_in6 csin6;
memset(&csin6, 0, sizeof(struct sockaddr_in6));
int sin6size = sizeof(struct sockaddr_in6);
//Accept a communication
printf("Wait for communication\n");
csock = accept(sock, (struct sockaddr *) &csin6, &sin6size);
printf("Connection accepted\n");
char msg[16];
sprintf(msg, "CONNECTED - %zu\n", clientID);
send(csock, msg, sizeof(msg), 0);
printf("Client %zu connected\n", clientID);
//Handle client
--snip--
}
So this is a basic connection with socket using connected communication. The server handle several client in the while loop thanks to threading.
Here the code of the client:
void *sender(void *arg)
{
int socket = (int)(long)arg;
char buffer[BUFF_SIZE];
while(1)
{
scanf("%s", buffer);
send(socket, buffer, strlen(buffer), 0);
bzero(buffer, BUFF_SIZE);
}
}
int main(int argc, char *argv[])
{
if(argc < 2)
errx(EXIT_FAILURE, "Usage: ./client <server ip>\n");
//Create the socket
int sock = socket(AF_INET6, SOCK_STREAM, 0);
struct hostent *hostinfo = NULL;
hostinfo = gethostbyname2(argv[1], AF_INET6);
if(hostinfo == NULL)
errx(EXIT_FAILURE, "Can't connect to the server\n");
//Set up the socket interface
struct sockaddr_in6 sin6 = { 0 };
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(PORT);
sin6.sin6_addr = *(struct in6_addr *)hostinfo->h_addr;
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
{
perror("connect()");
errx(EXIT_FAILURE, "Fail to connect");
}
printf("Connection established\n");
pthread_t sending;
if(pthread_create(&sending, NULL, sender, (void *)(long)sock) != 0)
printf("Fail to create a thread\n");
//Handle reception
char buffer[BUFF_SIZE];
int n;
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
{
buffer[n] = '\0';
printf("%s", buffer);
}
printf("Erreur: %d\nConnection broken\n", n);
pthread_cancel(sending);
close(sock);
return EXIT_SUCCESS;
}
So I start the client with:
~ ./client ::1
The output is the following:
Connection established
Error: -1
Connection broken
While the server is still "Waiting for communication". This means that the server do not accept the connection but the client succeed to connect.
Thank you for you help.
It is probably already the connect(), which fails here:
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
SO_ERROR is not meant to be used here, but as a socket option when retrieving the error when an asynchronous connect fails. A (synchronous) connect() returns -1 on error and sets errno, so do
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == -1) {
...
Later, the recv here:
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
fails with errno ENOTCONN, since the connection failed beforehand.
The same SO_ERROR mistake is present at various locations in your server code; it is possible, that already the bind() there fails! The call to listen() will then autobind it to a free ephemereal port, so the call as well as the call to accept() will succeed.
Why can the call to bind() fail? You might have to set the socket option SO_REUSEADDR when (re-)starting the server, otherwise it might refuse to use a recently bound port if connections are still in TIME_WAIT state. Place this directly before the bind() call:
int one = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
This might help.
I have a simple tcp client server program. Client sends text, server prints it ito terminal. I need to make it so client can connect to server by ip address, no just a port. Tried changing something in my localhost server, but it only broke it and it doesn't work anymore. What's whong in it?
Here's the server code:
int server(int port)
{
int fd;
struct ifreq ifr;
char * addres;
fd = socket(AF_INET, SOCK_STREAM, 0);
/* I want to get an IPv4 IP address */
ifr.ifr_addr.sa_family = AF_INET;
/* I want IP address attached to "eth0" */
strncpy(ifr.ifr_name, "em0", IFNAMSIZ-1);
ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);
addres=inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
//until this part, i'm getting my em0 address to a variable which I want to use later
//to specify on which address I want my server to be
int s, s2, t, len;
int z;
struct sockaddr_in local, remote;
char str[100];
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
local.sin_family = AF_INET;
local.sin_addr.s_addr = inet_addr(addres); //inet_addr(inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
printf("binder");
if (bind(s, (struct sockaddr *)&local, sizeof(local)) == -1) {
perror("bind");
exit(1);
}
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
for(;;) {
int done, n;
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((s2 = accept(s, (struct sockaddr *) &remote, (socklen_t *) &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected...\n");
done = 0;
do {
n = recv(s2, str, 100, 0);
if (n <= 0) {
if (n < 0) perror("recv");
done = 1;
}
if (!done)
printf("%s", str);
fflush(stdout);
sleep(1);
} while (!done);
close(s2);
}
return 0;
}
It should start listening at given port, and on em0 interface address, but it seems to be doing nothing at all. In driver function I just pass the int representing port which I want to use.
Can I connect my client with that server using ip address?
My driver funtion chooses if I want to start a server or a client, it's all in one file.
To start a server i use:
./main.o -l [port]
and to start a client I'd want to use:
./main.o [address] [port]
Client seems to be working fine, just refuses to connect, only problem (as far as I'm aware) is a server. Maybe you'll catch what am I doing wrong, I'm sitting with it for couple of hours basically hopeless.
I have written the following code as an intermediate to connect two programs. There is a server program running and a client program on two different systems. This code is expected to act as an intermediate between these two programs.
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
//Connect with program on server side
char * serv_con(char app_data[50])
{
int sock, bytes_recieved;
char send_data[1024];
char *recv_data = malloc(1024);
struct hostent *host;
struct sockaddr_in server_addr;
host = gethostbyname("10.47.3.249");
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(3128);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(server_addr.sin_zero),8);
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
perror("Connect");
exit(1);
}
bytes_recieved=recv(sock,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';
send(sock, app_data, 50, 0);
return recv_data;
//close(sock);
}
//Connect with client app
char * cli_con(char ser_data[50])
{
int sock, connected, bytes_recieved , true = 1;
char send_data [1024];
char *recv_data = malloc(1024);
struct sockaddr_in server_addr,client_addr;
int sin_size;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket");
exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1)
{
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5000);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
perror("Unable to bind1");
exit(1);
}
if (listen(sock, 5) == -1)
{
perror("Listen");
exit(1);
}
sin_size = sizeof(struct sockaddr_in);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size1);
printf("\n I got a connection from (%s , %d)",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
bytes_recieved = recv(connected,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';
send(connected, ser_data,50, 0);
//close(sock);
}
int main()
{
char *ser_data, *app_data;
int pid = fork();
while(1)
{
if(pid == 0)
app_data = serv_con(ser_data);
else
ser_data = cli_con(app_data);
}
}
It works fine until the client side app runs. But as soon as the client side app runs, the code exit giving the error:
Unable to bind: Address already in use
I got a connection from (192.168.0.3 , 45691)
What modification should I make in the code to rectify this error? I am working on linux. Thanks in advance.
EDIT:
I have removved the comment from close(sock)and added close(connect) in the function cli_con. The code on the client side is given below:
int sock, bytes_recieved;
char send_data[1024],recv_data[1024];
struct hostent *host;
struct sockaddr_in server_addr;
host = gethostbyname("192.168.0.2");
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5555);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(server_addr.sin_zero),8);
if (connect(sock, (struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1)
{
perror("Connect");
exit(1);
}
while(1)
{
//necessary codes
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
close(sock);
goto connct;
}
}
But now on running, the first program doesnot exit but doesnot even print
I got a connection from (192.168.0.3 , 45691)
But just keeps on running without printing ANY messages. But on the other hand, the client exits showing the error:
Connect: Connection reset by peer
What should I do now?
When a client disconnects you create a new server socket and bind it to the same port. If the server side socket was not closed the port is still in use, so bind fails.
Usually the server side of a socket program has a loop around accept to allow it process connections from many clients. This way bind and listen are called only once.
while (connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size1)) {
printf("\n I got a connection from (%s , %d)",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
bytes_recieved = recv(connected,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';
send(connected, ser_data,50, 0);
close(connected);
}
It means you're trying to listen on port 5000, but there is already a program listening on that port (possibly an earlier version of your program which didn't close the port properly.) Change the port number to another value, or close any application listening on the port.
Since you're under Linux, you can use "netstat -nlp" as root to see what programs have which ports open.
One pointer for you is that, you should close both the listen socket and the socket which you obtain from the accept call.
close(connected);
close(sock);
Also, the socket takes sometime to be freed by the OS after it's usage and so, it might fail with an "Address already in use" error. You can check again properly in your code if your SO_REUSEADDR part of the code is executing properly.
Also, since you can try to add the listen socket creation code in your main function itself and pass it as an argument to cli_con function. Commonly followed mechanism is to create one listen socket and use it to accept multiple connections from client.
I hope in your original code you have proper memory allocation, initialization etc for ser_data & app_data.
I'm making a client program in C that has to deal with this situation:
1- server program receives udp datagram in port no 8080 sent by client with a port number X
2- server creates a new socket (TCP) in port number X
3- using this TCP socket, server reads a string sent by the client
(running on localhost)
I don't need to make the server program, it's already done. The points 1 and 2 are covered, but I've been a couple of days trying to work out the 3rd point and I'm not able to make it work ><
The code I've got for the client is this:
#define MYPORT 8080
int main(int argc, char *argv[ ]) {
int sockfd;
/* connector’s address information */
struct sockaddr_in their_addr;
struct hostent *he;
int numbytes;
int sockfd2, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc != 3) {
fprintf(stderr, "Usage: %s <hostname> <message>\n", argv[0]);
exit(1);
}
/* get the host info */
if ((he = gethostbyname(argv[1])) == NULL) {
perror("Error obtaining the client. \n");
exit(1);
}
else printf("Client obtained\n");
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Error creating UDP socket\n");
exit(1);
}
else printf("UDP Socket done\n");
their_addr.sin_family = AF_INET;
printf("Port: 8080\n");
their_addr.sin_port = htons(MYPORT);
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
memset(&(their_addr.sin_zero), '\0', 8);
sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd2 < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
//sending port where the TCP socket will be associated
//server client connects correctly to this port
//and the code it's working fine in this point
if((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1)
{
perror("Client-sendto() error lol!");
exit(1);
}
//port is sent, now let's connect to the port by tcp and write the string
//not working properly from now on
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(atoi(argv[2]));
if (bind(sockfd2,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
listen(sockfd2, 5);
accept(sockfd2, 0, 0);
printf("accepted!\n");
//sending the string to the TCP Port...
if((numbytes = sendto(sockfd2, "hi", 2, 0, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr))) == -1)
{
printf("Client-sendto()-TCP error\n");
exit(1);
}
if (close(sockfd) != 0) printf("Client-sockfd-UDP closing is failed!\n");
else printf("Client-sockfd-UDP successfully closed!\n");
if (close(sockfd) != 0) printf("Client-sockfd2-TCP closing is failed!\n");
else printf("Client-sockfd2-TCP successfully closed!\n");
return 0;
}
The code works for the first two steps, but in the last step, it seems it's not connecting well with the TCP port, because my client program ends but my server program says that he receives null.
And of course I'm always sending ports > 1024
Thanks in advance, any help will be so appreciated.
listen(sockfd2, 5);
accept(sockfd2, 0, 0);
printf("accepted!\n");
I haven't read all your code, but the above (at least) is wrong. You absolutely need to retain the return value of accept: it's the socket you need to write to!
accept returns a file descriptor for the new TCP socket that has just been created for communicating with the "server" in your case. You need to use that as the file descriptor you write your string to.
(The sendto call just after that, apart from using the wrong socket, is a bit suspicious since the server will have no way to determine how much data to read/where the message stops. Passing a length of 3 (to include the \0 byte, would be a bit less suspicious.)