I suspect this has an easy solution I'm overlooking, probably to do with the client or how this is set up.
Anyways, I'm trying to set up a simple Echo server/client to understand the basics of socket programming. I have a virtual machine running Linux Mint, and the host is running Windows 10. The virtual machine I am setting to run the server c code, and the Windows will be running the client.
I started off making the server code
//Echo Server for UNIX: Using socket programming in C, a client sends a string
//to this server, and the server responds with the same string sent back to the client
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
int main()
{
char stringBuffer[50]; //string buffer for reading incoming and resending
int listener, communicator, c; //store values returned by socket system call
if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) //creates a new socket
puts("Could not create socket");
puts("Socket Created");
struct sockaddr_in servAddr, client; //structure from <netinet/in.h> for address of server
servAddr.sin_family = AF_INET; //addressing scheme set to IP
servAddr.sin_port = htons(8888); //server listens to port 5000
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //symbolic constant of server IP address
//binds the socket to the address of the current host and port# the server will run on
if (bind(listener, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0){
puts("Bind failed");
return 1;
}
puts("Bind Successful");
listen(listener, 5); //listens for up to 5 connections at a time
c = sizeof(struct sockaddr_in);
if ((communicator = accept(listener, (struct sockaddr*)&client, (socklen_t*)&c ))<0)
puts("accept failed");
puts("Connection Accepted");
//wait until someone wants to connect, then whatever is sent can be read from communicator, which can then be sent back
while(1){
bzero(stringBuffer, 50); //sets buffer to 0
read(communicator, stringBuffer, 50); //reads from communicator into buffer
write(communicator, stringBuffer, strlen(stringBuffer)+1); //returns back
}
return 0;
}
after that I tested it out by opening another terminal in the guest machine and typed "telnet localhost 8888" and input whatever strings I wanted.
This test worked so now, onto my Windows machine to create the client side of the socket programming:
#include <winsock.h>
#include <stdio.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int main(int argc, char *argv[])
{
WSADATA wsadata; //variable for using sockets in windows
SOCKET sock; //socket variable for network commands
char sendString[50], recieveString[50]; //variables for sending and recieving messages to/from server
//check if WSA initialises correctly
if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0)
printf("Error Code: %d", WSAGetLastError());
//creates new socket and saves into sock
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
printf("Could not create socket: %d", WSAGetLastError());
printf("Socket created\n");
struct sockaddr_in servAddr;
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //sets the IP address to the same machine as the server
servAddr.sin_family = AF_INET; //addressing scheme set to TCP/IP
servAddr.sin_port = htons(8888); //server address is on port 8888
//connects to device with specifications from servAddr
if (connect(sock, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
printf("Connection Error %d\n", WSAGetLastError());
return 1;
}
printf("Connection Accepted\n");
while(1){
fgets(sendString, 50, stdin); //uses stdin to get input to put into sendString
//sends sendString to server using sock's properties
if (send(sock, sendString, strlen(sendString) + 1, 0) < 0); {
printf("Send Failed");
return 0;
}
//reads from server into recieveString
if ((recv(sock, recieveString, 50, 0)) == SOCKET_ERROR)
printf("Recieve Failed");
printf("%s", recieveString); //prints out recieveString
}
}
Now, with the server still running, when I try out the client-side, I get the response "Connection Error" (from line 35). Having looked at both Unix and WinSock examples, I'm unsure as to why I would be failing the connection. I suspect it might have something to do with a windows to linux VM but I'm not sure.
---UPDATE---
Having updated the accidental semicolon and added the WSAGetLastError, it's showing an error code of 10061; This translates to
"Connection refused.
No connection could be made because the target computer actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host—that is, one with no server application running."
[after the 3rd edit:]
Sry, just re-read your question. The important thing is here:
The virtual machine I am setting to run the server c code, and the Windows will be running the client.
127.0.0.1 is an address always only local to an IP enabled box. So you your server is listening on the interface 127.0.0.1 local to the Linux VM and the client tries to connect to 127.0.0.0 local to the Windows box. Those two interfaces are not the same. The result is the obvious, namely the client does not find anything to connect to.
127.0.0.1 (the so called "IPv4 local loopback interface") can only be used for connections local to exactly one box.
if (connect(sock, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0); {
printf("Connection Error");
return 1;
}
This is just a trivial syntax mistake. You are entering the block unconditionally. Remove the first semicolon.
However there is a much more important point to be made. When you get an error from a system call such as connect(), you must print the error. Not just some message of your own devising. Otherwise you don't know whether you simply have a bug, or a temporary problem, or a long-lasting problem, or a permanent problem.
Change the printf() to:
printf("Connect error %s\n", WSAGetLastError());
and then don't continue as though the error didn't happen.
Note that this applies to all system calls, specifically including socket(), bind(), listen(), connect(), accept(), recv(), send(), and friends.
Related
The following server in C doesn't work as expected. Upon running it the first time, no issues occur. Every next time you run it, it fails to bind. The solution of the question that some of you will probably mark as duplicate doesn't work either, regardless of the fact that setsockopt(...) is successful.
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define PORT 8080
#define SA struct sockaddr
int main() {
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1) puts("Socket creation failed."), exit(0);
else puts("Socket created.");
const int optVal = 1;
const socklen_t optLen = sizeof(optVal);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optVal, optLen);
servaddr.sin_family = AF_INET, servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (SA *) &servaddr, sizeof(servaddr))) {
puts("Bind failed.");
shutdown(sockfd, 2);
return 12;
}
else puts("Bound.");
if(listen(sockfd, 5)) puts("Listen failed."), exit(2);
else puts("Listening: ");
int len = sizeof(cli);
connfd = accept(sockfd, (SA*)&cli, &len);
if(connfd < 0) puts("Connection failed."), exit(3);
else puts("Accepted.");
close(connfd);
return 0;
}
Things I've tried so far:
using setsockopt(...) has no effect
shutdown(...) doesn't work either
closesocket(...) is part of the Windows API, which I just have no intention to use
If I decide to ignore the "Address already in use" error, accept(...) fails with Invalid argument
If it matters I'm using CLion with cygwin under Windows 10.
"If it matters I'm using CLion with cygwin under Windows 10."
I strongly suspect that this matters.
When I compile your code exactly as you posted it, it behaves according to your desired / expected behavior.
When I comment out the setsockopt() call, I need to wait until the TIME_WAIT expires before being able to re-bind the same address+port, which is also expected.
I'm using gcc on macOS, so I suspect that your compilation and/or runtime environment has something to do with your code not working as expected for you. One way you could verify this if you don't have access to a physical Linux machine, and if you cannot set up dual-boot on the Windows machine that you do have, would be to spin up a small Linux instance at Digital Ocean, AWS, or some other cloud provider.
EDIT #1
I repeated this on a DO Linux host, and I have confirmed that your original code works as expected.
I'm learning socket programming in C. I have gotten my server to create a socket that was successful, but when I try to bind my socket to a port nothing happens. No error occurs and it is not successful. It's as if the bind() function is not even executing at all.
I've checked out the documentation on the bind() function here but there's no mention of why it won't execute at all. I've also tried searching through this site with no avail.
I also tried following this tutorial from start to finish but the error (or lack thereof) still occurs.
Here is my full code leading up to the problem:
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "include.h"
int main() {
// Descriptors. Used to check the status of functions such as socket, listen, bind etc.
// If a descriptor is equal to 0, then everything is okay. Else, if they are equal to -1, something went wrong.
int socketDescriptor, newSocketDescriptor = 1;
// The process ID of a child process (the client) when a new one is spawned (the client connects).
pid_t childPID;
// A string to hold the commands being sent a received.
char* commandBuffer = calloc(BUFFER_SIZE, sizeof(char));
// A structure to hold information on the server address.
struct sockaddr_in serverAddress;
memset(&serverAddress, '\0', sizeof(serverAddress));
// Fill in the server address information.
// Set the address family to AF_INET, which specifies we will be using IPv4.
// htons() takes the given int and converts it to the appropriate format. Used for port numbers.
// inet_addr() takes the given string and converts it to the appropriate format. Used for IP addresses.
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
// A structure to hold information a client when a new one connects to this server.
struct sockaddr_in clientAddress;
memset(&clientAddress, '\0', sizeof(clientAddress));
// socklen_t defines the length of a socket structure. Need this for the accept() function.
socklen_t addressSize;
// Creating the socket.
// AF_NET specifies that we will be using IPv4 addressing.
// SOCK_STREAM specifies that we will be using TCP to communicate.
socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
if (socketDescriptor < 0) {
perror("ERROR CREATING SOCKET");
exit(1);
}
else
printf("Socket created successfully.\n");
// Binding to the specified port. 0 if everything is fine, -1 if there was an error.
if (bind(socketDescriptor, (struct sockaddr*) & serverAddress, sizeof(struct sockaddr_in)) < 0) {
perror("ERROR BINDNING");
exit(1);
}
else
printf("Socket bound to %s:%s.\n", serverAddress.sin_addr.s_addr, serverAddress.sin_port);
The last if statement at the bottom is where the code fails. It should either print and error or print "Socket bound to 127.0.0.1:80" but neither happens. See an example here.
I'm lost for what to do.
A server socket won't show up in a netstat listing unless you call listen after binding the socket.
Also, you're using the %s format specifier in your printf after the bind call on serverAddress.sin_addr.s_addr and serverAddress.sin_port. These are not strings but integers. Using the wrong format specifier invokes undefined behavior and is likely causing your program to crash. Using the correct format specifier such as %d or %x will fix this.
if (bind(socketDescriptor, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr_in)) < 0) {
perror("ERROR BINDNING");
exit(1);
}
else
// use %x to print instead
printf("Socket bound to %x:%x.\n", serverAddress.sin_addr.s_addr, serverAddress.sin_port);
if (listen(socketDescriptor, 3) < 0) {
perror("listen failed");
} else {
printf("socket is listening\n");
}
Everything compiles without errors and warnings. I start the program. I visit localhost:8080 and the program stops - great. I try to run the program again and I get Error: unable to bind message. Why?
Code:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PORT 8080
#define PROTOCOL 0
#define BACKLOG 10
int main()
{
int fd;
int connfd;
struct sockaddr_in addr; // For bind()
struct sockaddr_in cliaddr; // For accept()
socklen_t cliaddrlen = sizeof(cliaddr);
// Open a socket
fd = socket(AF_INET, SOCK_STREAM, PROTOCOL);
if (fd == -1) {
printf("Error: unable to open a socket\n");
exit(1);
}
// Create an address
//memset(&addr, 0, sizeof addr);
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
if ((bind(fd, (struct sockaddr *)&addr, sizeof(addr))) == -1) {
printf("Error: unable to bind\n");
printf("Error code: %d\n", errno);
exit(1);
}
// List for connections
if ((listen(fd, BACKLOG)) == -1) {
printf("Error: unable to listen for connections\n");
printf("Error code: %d\n", errno);
exit(1);
}
// Accept connections
connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
if (connfd == -1) {
printf("Error: unable to accept connections\n");
printf("Error code: %d\n", errno);
exit(1);
}
//read(connfd, buffer, bufferlen);
//write(connfd, data, datalen);
// close(connfd);
return 0;
}
Use the SO_REUSEADDR socket option before calling bind(), in case you have old connections in TIME_WAIT or CLOSE_WAIT state.
Uses of SO_REUSEADDR?
In order to find out why, you need to print the error; the most likely reason is that another program is already using the port (netstat can tell you).
Your print problem is that C format strings use %, not &. Replace the character in your print string, and it should work.
First, have a look into the following example:
Socket Server Example
Second: The reason why the second bind fails is, because your application crashed, the socket is still bound for a number of seconds or even minutes.
Check with the "netstat" command if the connection is still open.
Try putting the following code just before bind()
int opt = 1;
if (setsockopt(<Master socket FD>, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt))<0) {perror("setsockopt");exit(EXIT_FAILURE);}if(setsockopt(<Master socket FD>, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(opt))<0) {
perror("setsockopt");exit(EXIT_FAILURE);}
Reason behind socket bind error 98:
Socket is 4 tuple (server ip, server port , client ip, client port)
When any two sockets tuples matches , error 98 is thrown
When you terminate the code on server side, it means you are ending connection with tcp client .
Now server is the one which sends FIN to client and goes to TIME_WAIT state.
Typically , in TIME_WAIT sate server sends ack packets continuously to client , assuming that if any ack gets lost in between .
Time out it depends on implementation of code . It could be from 30 seconds to 2 minutes or more.
If you run the code again , server is in TIME_WAIT , hecne port is already in use . This is because any service running on server will use fixed port which is not the case with client .
That is why in real life, server will never send FIN to client .It is client who sends FIN in order to end connection.
Even if client connects again before timeout of TIME_WAIT, he will be connected to server because , he will use now a different port thus socket tuple changes .
If it is implemented in reverse way , if server sends FIN , there after any new connection would not be accept till timeout ends .
Why port is busy ?
It is because in TIME_Wait , the one who sends FIN first, must transmit ack packets continuously till timeout expires.
I have a client connected to the server (TCP connection). In the case when server crashes (I disconnect it) my client needs to be connected to another server, in order to continue service. But when the first server comes back, I need to reconnect client to it again.
I was able to connect my client to the back up server after the first server crashes, but I have a problem with reconnecting my client to the first server. I made a function create_newconnect() for reconnecting to the server, but it doesn't work (that is why I'm not calling it in the code)
I tried to simplify my program as much as I could, so it wouldn't be to big
This is a client side
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <string.h>
#include <arpa/inet.h>
#include <time.h>
#define SIZE sizeof(struct sockaddr_in)
struct sockaddr_in server;
void tcp_protocol();//execute client tcp protocol
void server_check();
void tcp();
void create_newconnect();
int main (int argc, char *argv[])
{
int portno;
//Test for correct number of arguments
if (argc != 3)
{
fprintf(stderr, "Usage: %s Port# IP Address \n", argv[0]);
exit(1);
}
portno = atoi(argv[1]);//convert port # to int
server.sin_family = AF_INET;
server.sin_port = htons(portno);
server.sin_addr.s_addr = inet_addr(argv[2]);//use client ip address
tcp();//call tcp function
return 0;
}
void tcp()
{
int sockfd;
char c ;
//create socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0))==-1)
{
perror ("socket call faild");
exit (1);
}
//connect to the server
if (connect (sockfd, (struct sockaddr *)&server, SIZE)==-1)
{
perror ("connect call faild");
exit (1);
}
while(1)
{
printf("Enter char\n");
scanf("%c",&c);
server_check(sockfd);
//send packet to server
if (send(sockfd, &c, sizeof(c),0)<0)
{
printf("error sending\n");
}
//if packet is received from server
if(recv(sockfd, &c, sizeof(c),0)>0)
{
printf("server's respond %c\n", c);//print result
}
}
close(sockfd);
}
void server_check(int sock)
{
char b ='b';
//send packet to server
if (send(sock, &b, sizeof(b),0)<0)
printf("error sending\n");
//if packet is received from server
if((recv(sock, &b, sizeof(b),0)>0))
{
printf("server responded\n");
}
else//if server is not responding
{
printf("server crashed\n");
close(sock);//close socket
server.sin_port = htons(5002);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
tcp();//create new connection
}
}
void create_newconnect()
{
int newsockfd;
server.sin_port = htons(5001);
//create socket
if ((newsockfd = socket(AF_INET, SOCK_STREAM, 0))==-1)
{
perror ("socket call faild");
exit (1);
}
//connect to the server
if (connect (newsockfd, (struct sockaddr *)&server, SIZE)==-1)
{
perror ("connect call faild");
exit (1);
}
tcp();//call function to execute tcp protocol
}
I think the first thing you're going to have to consider is: after your first server has crashed and your client has successfully reconnected to the backup server, how would your client ever know that that the first server has come back on line?
I can think of two possibilities: one might be that the backup server might notify the client about the re-appearance of the primary server (e.g. by sending some sort of PRIMARY_SERVER_ONLINE message over the TCP connection, or perhaps simply by closing the TCP connection, with the expectation that that would cause the client to try to connect to the primary server again).
The other approach would be to make your client smart enough that it can periodically (e.g. once per minute) try to reconnect to the primary server even while it is using the TCP connection to the backup server. That is doable, but not with a single thread and blocking I/O like your posted code has... (because if your program is blocked in a recv() call, there is no way for it to do anything else like try to connect a TCP connection). You'd need to either use non-blocking I/O and select() (or similar), or asynchronous I/O, or multiple threads, in order to do it properly.
Your program recursively calls tcp() after reconnecting. This is almost certainly not correct and will result in resource (mainly stack) use on each disconnection.
You need to avoid having the code pass the socket file descriptor (sockfd) by value to the functions as it will change after each new connection.
As a general principle, you can have a list of (two or more) hosts in order of preference. Then, at all times attempt to create connections to those that have higher preference than the one you currently have a connection to. Then, when a connection is established, close all the other open sessions, and switch to the new preferred connection.
Keep this encapsulated and have it return the current active sockfd for use by all the other functions.
I'm learning from the book Hacking, the Art of Exploitation by Jon Erickson, and I am confused regarding to a simple code sample that he provided. The code is to set up a simple server, but when I complied it (no error) and ran the code, it hangs
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "hacking.h"
#define PORT 7890 // the port users will be connecting to
int main(void) {
int sockfd, new_sockfd; // listen on sock_fd, new connection on new_fd
struct sockaddr_in host_addr, client_addr; // my address information
socklen_t sin_size;
int recv_length=1, yes=1;
char buffer[1024];
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
fatal("in socket");
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
fatal("setting socket option SO_REUSEADDR");
host_addr.sin_family = AF_INET; // host byte order
host_addr.sin_port = htons(PORT); // short, network byte order
host_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(host_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(sockfd, (struct sockaddr *)&host_addr, sizeof(struct sockaddr)) == -1)
fatal("binding to socket");
if (listen(sockfd, 5) == -1)
fatal("listening on socket");
while(1) { // Accept loop
sin_size = sizeof(struct sockaddr_in);
new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
if(new_sockfd == -1)
fatal("accepting connection");
printf("server: got connection from %s port %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
send(new_sockfd, "Hello World!\n", 13, 0);
recv_length = recv(new_sockfd, &buffer, 1024, 0);
while(recv_length > 0) {
printf("RECV: %d bytes\n", recv_length);
dump(buffer, recv_length);
recv_length = recv(new_sockfd, &buffer, 1024, 0);
}
close(new_sockfd);
}
return 0;
}
I did a little printf() to find out where I hangs, and it turns out to be on this line
sin_size = sizeof(struct sockaddr_in);
I'm not sure if it has to do with my environment, or there is something that I am missing. The environment that the book uses can no longer be updated (some old verson of Ubuntu). So I am currently using the latest one.
Can someone please explain to me why the program does not work?
And if there is some basic that need to know before learning the network chapter, please do tell.
This program won't proceed until accept on the line after the sizeof receives an incoming connection from a client program. Your printf shows that accept was called but was blocked.
You need to compile and run the client with the right options (IP / Port) to connect to this server program.
Update
If 192.168.42.248 is from the book, then you're probably trying to connect to the wrong IP. Try telnet 127.0.0.1 7890.
It's a server, it will "hang" until you make a connection to port 7890. That's the whole point of the program (for more detais, it blocks since accept() is waiting for a connection)
Assuming you are running unix, try to type echo "hi there" | nc localhost 7890 in a terminal from the same machine while you run it, and you will see how it "unblocks"
Telling by all the comments flying around in your thread I'd recommend to connect with telnet using the following command line: telnet localhost 7890
telnet takes as arguments the host to connect to and the port to connect to on this host. Using "localhost" is similar to using the loopback IP 127.0.0.1.
Why does connecting to the server solve the "hang"? accept is blocking as you can read in the man page or any other documentation of your programming environment. This means the function won't return until a client connects. After connecting the function returns a handle to the socket created for the connecting client which can be used to communicate.