I am working in a simple socket project. I would like to know:
why error messages appear before telnet localhost 5678?
why SO_REUSEADDR (between socket() and bind()) don't work, and what else I should try?
Code Output Message:
bind error
Error opening file: Address already in use
telnet localhost 5678
[+]Server Socket is created.
main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#define BUFSIZE 1024 // Buffer Size
#define PORT 5678
int main() {
printf("telnet localhost 5678\n");
int rfd; // socket descriptor
int clientfd; // client descriptor
struct sockaddr_in client; // Client Socket address
socklen_t client_len; // Length of Client Data
char input[BUFSIZE]; // Client Data -> Server
int bytes_read; // Client Bytes
// 1. socket() = create a socket, SOCK_STREAM = TCP
rfd = socket(AF_INET, SOCK_STREAM, 0);
if (rfd < 0) {
fprintf(stderr, "socket error\n");
exit(-1);
}
printf("[+]Server Socket is created.\n");
// optional
int enable = 1;
if (setsockopt(rfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
fprintf(stderr, "setsockopt(SO_REUSEADDR) failed");
//Initialize the server address by the port and IP
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET; // Internet address family: v4 address
server.sin_addr.s_addr = INADDR_ANY; // Server IP address
server.sin_port = htons(PORT); // Server port
// 2. bind() = bind the socket to an address
int brt = bind(rfd, (struct sockaddr *) &server, sizeof(server));
if (brt < 0) {
int errnum;
errnum = errno;
fprintf(stderr, "bind error\n");
fprintf(stderr, "Error opening file: %s\n", strerror(errnum));
exit(-1);
}
printf("[+]Bind to port %d\n", PORT);
// 3. listen() = listen for connections
int lrt = listen(rfd, 50);
if (lrt < 0) {
printf("listen error\n");
exit(-1);
}
if (lrt == 0) {
printf("[+]Listening....\n");
}
// non-stop loop
while (1) {
// 4. accept() = accept a new connection on socket from client
clientfd = accept(rfd, (struct sockaddr *) &client, &client_len);
if (clientfd < 0) {
fprintf(stderr, "accept failed with error %d\n");
exit(-1);
}
printf("Client connected\n");
...
close(clientfd);
printf("Client disconnected\n");
}
close(rfd);
}
I'm assuming that you are using Linux. If you want to rebind to an address, you should use SO_REUSEPORT not SO_REUSEADDR. Name is really misleading. But make sure that you know how it works and whether you really want to use it or not.
You can check difference here: How do SO_REUSEADDR and SO_REUSEPORT differ?
Related
I'm trying to launch multiple servers, at once, in a c program. For the sake of simplicity let's say 5 servers.
If I understand well the sockets, each of them must be listening to a different IP socket address (different PORT, different IP interface address).
I thought to do that inside a loop, incrementing port number by i at each turn. Here's my current code just to launch one server. I know it's possible with bash by launching the same process in background, but in C I really don't know how to do that and if it's even possible
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
long PORT;
int main(int argc, char const *argv[])
{
/* 1. Open a socket
2. Bind to a address(and port).
3. Listen for incoming connections.
4. Accept connections
5. Read/Send
*/
int listenerSocket; /* socket for accepting connections */
int clientSocket; /* socket connected to client */
struct sockaddr_in server;
struct sockaddr_in client; /* client address information */
char buf[100]; /* buffer for sending & receiving data */
int errnum;
listenerSocket = socket(AF_INET, SOCK_STREAM, 0);
if(listenerSocket == -1){
perror("erreur lors de la création du socket");
}
PORT = strtol(argv[1], NULL, 10);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port= htons(PORT);
if (bind(listenerSocket, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
puts("Server waiting for connection...");
while(1){
if (listen(listenerSocket, 5) < 0){
perror("listen failed");
exit(EXIT_FAILURE);
}
int c = sizeof(client);
if((clientSocket = accept(listenerSocket, (struct sockaddr*) &client, &c)) < 0){
puts("error accepting the request");
perror("Accept()");
}
puts("connection accepted");
while(1){
if( recv(clientSocket, buf, sizeof(buf), 0) < 0) {
errnum = errno;
perror("Recv()");
printf("val printed by errno: %d\n",errno);
}
printf("Message : %s\n", buf);
}
if (send(clientSocket, buf, sizeof(buf), 0) < 0)
{
perror("Send()");
exit(7);
}
close(clientSocket);
close(listenerSocket);
printf("Server ended successfully\n");
exit(0);
}
I have an assignment where I need to create a simple HTTP server to handle GET requests and return info from a directory in the directory holding the executable for this code. I am trying to establish a connection between the sockets before ironing out the HTTP requests. However, when I try to connect the client to the server using accept() it triggers an infinite loop with gdb displaying this message:
../sysdeps/unix/sysv/linux/accept.c:26
26 ../sysdeps/unix/sysv/linux/accept.c: No such file or directory.
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
int main(int argc, char* argv[]){
if(argc>1){
perror("Error there should be no command line arguments");
exit(0);
}
int sockfd = 0;
int clientfd = 0;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))<0){ //create socket and check for error
perror("Error in socket creation");
exit(0);
}
//create sockaddr object to hold info about the socket
struct sockaddr_in server, client;
server.sin_family = AF_INET;
server.sin_port = 0;
server.sin_addr.s_addr = htonl(INADDR_ANY);
socklen_t sockSize = sizeof(server);
//Bind the socket to a physical address exit if there is an error
if((bind(sockfd, (struct sockaddr*)&server, sockSize))<0){
perror("Error binding socket");
exit(0);
}
//Check server details
printf("-------Server Details----------\n");
printf("Port number %d | IP ADDRESS %d\n", ntohs(server.sin_port), (getsockname(sockfd, (struct sockaddr*)&server, &sockSize)));
if((getsockname(sockfd, (struct sockaddr*)&server, &sockSize)) <0){
perror("There is an error in the sock");
exit(0);
}
if(listen(sockfd, 5) <0){
perror("Error switching socket to listen");
exit(0);
}
while((clientfd = accept(sockfd, (struct sockaddr*)&client, (socklen_t*)&sockSize))){
printf("Socket is awaiting connections");
}
// figure out how to setup client to accept and submit HTTP requests
close(sockfd);
return 0;
}
accept() returns -1 on failure. An if will treat any non-zero value as a true condition.
Your loop should look more like the following:
// setup listening socket...
printf("Socket is awaiting connections");
while (1) {
sockSize = sizeof(client); // <-- add this
if ((clientfd = accept(sockfd, (struct sockaddr*)&client, (socklen_t*)&sockSize)) < 0) {
if (errno != EINTR) {
// fatal error, bail out...
break;
}
continue; // retry...
}
printf("Client connected");
// use clientfd to read HTTP request and send HTTP response...
close(clientfd);
}
I have simple client/server program in socket in C. I use inet_ntoa that returns ip of clients connected to servers. I run a loop 2 times to connect 2 clients and store int in array of char.
The problem is that when I print the array it always gives the last ip added to the array. For example:
x.x.x.x connected
y.y.y.y connected
The array prints y.y.y.y two times
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
// Driver function
int main() {
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
struct sockaddr_in addr_remote;
char * ips[2];
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero( & servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA * ) & servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
int i = 0;
for (i = 0; i < 2; i++) {
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
len = sizeof(cli);
// Accept the data packet from client and verification
connfd = accept(sockfd, (SA * ) & addr_remote, & len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client...\n");
// Function for chatting between client and server
// func(connfd);
//printf( " Welcome %s " , inet_ntoa(addr_remote.sin_addr));
ips[i] = inet_ntoa(addr_remote.sin_addr);
}
for (i = 0; i < 2; i++) {
printf("%s", ips[i]);
}
// After chatting close the socket
close(sockfd);
}
You have to allocate Your own char array for IP and copy it from static buffer returned by inet_ntoa(). Simple example:
char ips[2][20];
...
strcpy(ips[i], inet_ntoa(...))
EDIT: The point is, that the inet_ntoa() function stores it's result to it's internal, statically allocated, buffer and returns just a pointer to it, which is constant. So Your ip[0] and ip[1] both contain the same pointer, which points to the last IP obtained from inet_ntoa().
I'm using C to implement a simple client-server retrieval system with Linux socket. I've now successfully connect the remote server, but when I close the connection, the server went down, i.e. the server program stopped.
What should I do avoid this?
here's sample of my code:
server:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
int main(void)
{
int optval;
socklen_t optlen = sizeof(optval);
char str[100] = "";
int listen_fd, conn_fd;
struct sockaddr_in servaddr;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
// check if on
getsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen);
printf("keep alive is %s\n", (optval? "ON" : "OFF"));
// set it on
optval = 1;
optlen = sizeof(optval);
setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);
printf("done, check again.\n");
printf("keep alive is %s\n", (optval? "ON" : "OFF"));
bzero( &servaddr, sizeof(servaddr));
// set appropriate protocol and port number (15792)
// the htons() function converts the unsigned short integer
// from host byte order to network byte order.
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(15792);
// Bind a name to a socket
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
// listening for incoming connection
listen(listen_fd, 10);
// accept a connection on a socket
conn_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
do
{
// set str to null
bzero(str, 100);
// Read from a file descriptor (linux all)
read(conn_fd,str,100);
// print the received message
// printf("Received: %s\n",str);
if (!strcmp(str, "GET TIME\n"))
{
bzero(str, 100);
time_t clocks;
clocks = time(NULL);
sprintf(str, "%s", ctime(&clocks));
write(conn_fd, str, strlen(str));
//close(conn_fd);
}
else
{
bzero(str, 100);
strcpy(str, "ERROR: No such command.\n");
write(conn_fd, str, strlen(str));
//close(conn_fd);
}
} while (1);
}
client:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char **argv)
{
// declare necessary variables
int sockfd;
char recv[1024] = "";
char command[100] = "";
struct sockaddr_in servaddr;
if (argc != 2)
{
printf("usage: %s <ip address>\n", argv[0]);
exit(EXIT_FAILURE);
}
// create a socket with the appropriate protocol
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("ERROR: Failed create cosket.\n");
exit(EXIT_FAILURE);
}
// Set all the socket structures with null values.
bzero(&servaddr, sizeof servaddr);
// set appropriate protocol and port number (1999)
// The htons() function converts the unsigned short integer
// hostshort from host byte order to network byte order.
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(15792);
// Convert IPv4 and IPv6 addresses from text to binary form
if (inet_pton(AF_INET, argv[1], &(servaddr.sin_addr)) <= 0)
{
printf("ERROR: Wrong ip address.\n");
exit(EXIT_FAILURE);
}
// attempt to connect to a socket
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
printf("ERROR: Failed at connect.\n");
exit(EXIT_FAILURE);
}
else
{
printf("------ connect successfull ------\n");
}
do
{
printf("> ");
fgets(command, 100, stdin);
write(sockfd, command, strlen(command));
if (!strcmp(command, "QUIT\n"))
{
close(sockfd);
break;
}
// print the receive stuff
read(sockfd, recv, sizeof(recv));
fputs(recv, stdout);
bzero(recv, 1024);
} while (1);
}
In your server code, the accept() function must be called in the do-while loop:
// listening for incoming connection
listen(listen_fd, 10);
do
{
// accept a connection on a socket
conn_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
...
close(conn_fd);
} while(1);
my question here is, why server ended if I close the connection from
the client.
Because then the blocking read call will return the value 0 indicating the connection was closed, which you promptly ignore. You then try (and fail) to compare the received data (which you have none) to the string and you will attempt to write the error message to the (now disconnected) client which will raise the SIGPIPE error which terminates your application.
– Some programmer dude
I'm trying to create TCP Server that should run on a machine with multiple NIC's (eth0, eth1). Each NIC has its own IP from the network and I basically want to be able to connect to the servers running on each of the IP's at the same time. However currently I am able only to connect (netcat) to the first interface IP eth0 and when I try with eth1 I get a "Connection refused" even when I have the server only running on eth1.
I'm not sure if it is a problem with my server code (below). I bind to the required interface with setsockopt() and also use the interface IP (retrieved via ioctl), and netstat shows that the server is listening on the correct ip:port, however I am not able to connect to the one on eth1.
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 255
struct in_addr getIfIp(char* ifName)
{
int sockfd;
struct ifreq ifr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0) {
fprintf(stderr, "ioctl failed\n");
}
close(sockfd);
return ((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr;
}
int startServer(char* ifName, unsigned short port)
{
int sock_descriptor, conn_desc;
struct sockaddr_in serv_addr, client_addr;
socklen_t size = sizeof(client_addr);
char buff[MAX_SIZE];
if (ifName == NULL || port == 0) {
fprintf(stderr, "invalid server parameters\n");
return -1;
}
sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);
if(sock_descriptor < 0) {
fprintf(stderr, "Failed creating socket\n");
return sock_descriptor;
}
if (setsockopt(sock_descriptor, SOL_SOCKET, SO_BINDTODEVICE, ifName, strlen(ifName)) < 0) {
fprintf(stderr, "Failed setting socket option\n");
return -1;
}
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; // AddressFamily = Internet address
serv_addr.sin_addr = getIfIp(ifName);//INADDR_ANY;
serv_addr.sin_port = htons(port);
// bind the address to the socket file descriptor
if (bind(sock_descriptor, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
fprintf(stderr, "Failed to bind\n");
return -1;
} else {
printf("bound to %s\n", inet_ntoa(serv_addr.sin_addr));
}
// Now start listening
if (listen(sock_descriptor, 0) < 0){
fprintf(stderr, "Listen failed");
return -1;
} else {// max queue of pending connections
printf("Listening on port %hu ...\n", port);
}
conn_desc = accept(sock_descriptor, (struct sockaddr *)&client_addr, &size);
if (conn_desc == -1) {
fprintf(stderr, "Failed accepting connection\n");
} else {
fprintf(stderr, "Connected\n");
}
close(conn_desc);
close(sock_descriptor);
return 0;
}
Any help with this would be appreciated.
[EDIT]
As mentioned in my comment, one funny thing I noticed is that once I connect to either of the interfaces I can only connect to this interface again and connect attempts to the other fail (for both eth0 and eth1) until a reboot.
Also I guess I would go ahead with INADDR_ANY for now but would really like to hear if anyone could shed some light as to why I can't connect to separate listeners (with my code here) in this case?
To have the socket listen on any interface use INADDR_ANY as listener address ...
serv_addr.sin_addr = INADDR_ANY;
and remove the call to setsockopt().
I'm not sure whether a back-log size of 0 makes sense. Also the code misses to test the outcome of the call to listen().
Finally int size should be socklen_t size.