I've just started learning the basics of sockets (Linux). I tried my hand at a small example, but it doesn't work and I have no idea what's wrong.
I get a "Connection Refused" error message.
Here's my code:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main() {
int c;
c = socket(AF_INET, SOCK_STREAM, 0);
if (c < 0) {
printf("Error in creating socket! %s\n", strerror(errno));
return 1;
}
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_port = htons(1234);
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("127.0.0.1"); //local host
if (connect(c, (struct sockaddr *)&server, sizeof(server)) < 0) {
// Here is my error
printf("Error when connecting! %s\n",strerror(errno));
return 1;
}
while(1) {
char msg[100];
printf("Give message: ");
fgets(msg, sizeof(msg), stdin);
send(c, &msg, sizeof(msg), 0);
char resp[100];
recv(c, &resp, sizeof(resp), 0);
printf("Received: %s\n", resp);
}
close(c);
}
EDIT
Of course ! the error was actually in the server. I simply found it weired that the client sent the message, so I narrowed my view, didn't even bother looking back at the server.
Since the error seems to be also in my server, I might end up asking another question and linking it here
Server was listening to (12345) ...
According to the man page:
ECONNREFUSED
No-one listening on the remote address.
In order to provide a simple remote endpoint that accepts your connection and sends back the received data (echo server), you could try something like this python server (or to use netcat):
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("localhost", 1234))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
data = conn.recv(1024)
if not data: break
conn.sendall(data)
conn.close()
Your Answer is: You program is client and it need a server to connect. nc command create server and your program can connect to it.
[root#mg0008 work]# nc -l 127.0.0.1 1234 &
[1] 25380
[root#mg0008 work]# ./socket
Give message: Hello
Hello
probably no server listening port 1234 in your local host
Related
I am trying to make a client-server communication using UNIX sockets and using the STREAM protocol.
My server is running fine, but my client is not working. Whenever I try to send or receive data, I get an error : "socket operation on non-socket". I really don't see where it comes from, because my server is very similar and I don't have any problem. My server is on my local machine (127.0.0.1) and port 5000. It is open and listening (I checked with the netstat command).
The code is there :
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#define CHECK(ret, mes) if ((ret) == -1) {perror(mes); exit(-1);}
#define STRING_LENGTH 250
int createSocketINETClient(short mode, char *addr, short port)
{
int s;
struct sockaddr_in moi, server;
int moi_len, server_len;
moi.sin_family = AF_INET;
moi.sin_port = htons(port);
moi.sin_addr.s_addr = inet_addr(addr);
memset(moi.sin_zero, 0, 8);
s = socket(AF_INET, mode, 0);
CHECK(s, "socket");
moi_len = sizeof(moi);
CHECK(bind(s, (struct sockaddr*) &moi, moi_len), "bind");
return s;
}
void infoSocket (int s)
{
struct sockaddr_in sock_addr;
socklen_t len = sizeof(sock_addr);
getsockname(s, (struct sockaddr*) &sock_addr, &len);
printf("Onfo of socket %d\n", s);
printf("\t IP : %s\n", inet_ntoa(sock_addr.sin_addr));
printf("\t port : %d\n\n", ntohs(sock_addr.sin_port));
}
int main ()
{
int bytes;
int sock = createSocketINETClient(SOCK_STREAM, "0.0.0.0", 0);
struct sockaddr_in serveurSock;
int client = 0, clientSockLen = 0;
char message[] = "I am a message that is supposed to WORK !!!!\n";
char fromServer[STRING_LENGTH] = "";
infoSocket(sock);
serveurSock.sin_family = AF_INET;
serveurSock.sin_port = htons(5000);
serveurSock.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(serveurSock.sin_zero, 0, 8);
CHECK(connect(sock, (struct sockaddr*) &serveurSock, sizeof(serveurSock)), "connect");
usleep(1000000);
CHECK((bytes = send(client, message, sizeof(message), 0)), "send");
printf("Message sent to server : %d bytes, \"%s\"\n", bytes, message);
CHECK((bytes = recv(client, fromServer, sizeof(fromServer), 0)), "recv");
printf("Message received from server : %d bytes, \"%s\"\n", bytes, fromServer);
close(client);
printf("Client released !\n\n");
return 0;
}
What did I do wrong ?
EDIT : The error comes from this line :
CHECK((bytes = send(client, message, sizeof(message), 0)), "send");
you are using the "client" variable as a socket parameter to sendto() when in fact you should use the "sock" variable.
should you strace the program, you could see the following:
connect(3, {sa_family=AF_INET, sin_port=htons(5000), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
nanosleep({tv_sec=1, tv_nsec=0}, NULL) = 0
sendto(0, "I am a message that is supposed "..., 46, 0, NULL, 0) = -1 ENOTSOCK (Socket operation on non-socket)
note the first sendto() parameter which is 0 (by default this is the stdin file descriptor) when in fact it should be 3 (see connect(...) line)
as a side note, you don't need to bind() the client socket unless you have an explicit reason to do so (using some other route than the default one, bypassing a firewall rule somewhere, etc). the os will assign by default the ip of the network interface the default route goes through and a random free port.
In the posted code you initialize int client = 0 and then I don't see you change it. So when you call send(0, ...) you obviously get that error.
As already mentioned by #EJP in comment to your question it can be a typo because it looks like you really was intended to use sock (as you connected it: connect(sock, ...) instead of client in call to send.
I wrote a simple application which connects to a given server on a given port. When the port is open, everything is ok, I got the message about the established connection. However, when the port is closed, nothing happens, my program does not show me the information about it.
I test my program using my remote server accessible via the Internet. How can I improve this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char **argv) {
char * ip_addr;
int port;
int sockfd;
struct sockaddr_in server_addr;
if (argc != 3)
{
fprintf(stderr,"Usage: ./canconnect ip port\n");
exit(1);
}
ip_addr = argv[1];
port = atoi(argv[2]);
if (port <= 0)
{
fprintf(stderr,"error: invalid port\n");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
inet_aton(ip_addr, &server_addr.sin_addr);
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect");
printf("Port %d is closed on server %s.\n", port, ip_addr);
exit(1);
}
else
{
printf("Connection established. Port %d is open on server %s.\n", port, ip_addr);
}
close(sockfd);
return 0; }
Given that the program actually prints some data after some time, it's most certainly has to do with timeout.
In order to finally decide that the host or the port is unreadable or the connection couldn't be established for any other reason, connect performs several attempts to connect and returns an error after a certain amount of time - the timeout.
The value of timeout can be changed to any value you want using setsockopt:
struct timeval timeout;
timeout.tv_sec = 3; // wait for three seconds
timeout.tv_usec = 0;
// set up receive timeout
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof(timeout)) < 0)
printf("[!] setsockopt failed\n");
If the remote server is reachable, but neither accepts nor refuses the connection, then connect() will block until the network connection attempt times out. As the Linux manual page for connect(2) puts it:
Note that for IP sockets the timeout may be very long when syncookies are enabled on the server.
Indeed, it is a well-known defense against port scans to attempt to elicit that behavior intentionally. You might be able to get quicker failures by using setsockopt() to set a receive timeout, but the docs are inconsistent on whether that will work for connect().
I got a task to implement a http server in c code.
it should include handling several connections, but for now I just want to make sure it works with just a single connection.
first, here is my code:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#define BUF_SIZE 1025
int main(int argc, char **argv)
{
uint16_t portNum = 80;
int connfd = 0, listenFd;
struct sockaddr_in serv_addr, peer_addr;
if ((listenFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket syscall failed: %s.\nExiting...\n", strerror(errno));
exit(EXIT_FAILURE);
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portNum);
if (bind(listenFd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)))
{
printf("bind syscall failed: %s\nExiting...\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (listen(listenFd, 5))
{
printf("listen syscall failed: %s\nExiting...\n", strerror(errno));
exit(EXIT_FAILURE);
}
while (1)
{
/* new connection */
socklen_t addrsize = sizeof(struct sockaddr_in);
connfd = accept(listenFd, (struct sockaddr *) &peer_addr, &addrsize);
if (connfd < 0)
{
printf("\n Error : Accept Failed. %s \n", strerror(errno));
return 1;
}
char httpRequest[BUF_SIZE] = {0};
if ((recv(connfd, httpRequest, BUF_SIZE, 0)) == -1)
{
printf("recv syscall failed: %s\nExiting...\n", strerror(errno));
exit(EXIT_FAILURE);
}
char msg[BUF_SIZE] = {0};
strcpy(msg, "200 OK THIS IS A TEST");
printf("sending message...\n");
int len = strlen(msg);
if (send(connfd, msg, len, 0) < 0)
{
printf("SEND ERROR\n");
exit(EXIT_FAILURE);
}
printf("message sent!\n");
close(connfd);
close(listenFd);
// THIS IS FOR DEBUG - ignore...
return 0;
}
return EXIT_SUCCESS;
}
here's my problem:
to test my code I ran the following command in another linux terminal:
curl -v loaclhost:80/~/ex.txt
(where ex.txt is simply a test file...)
here is the problem:
I see the http request both in the server and in the curl output, but it seems like the "send" command of the server doesn't work - in the curl window beneath the http rquest it says:
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server
any ideas?
Buffer of 1024 is too small for anything serious. For just playing locally it will work OK. If you ever want to do some serious work buffer of 8192 bytes works fine even for heavy loads.
recv() is in most implementations blocking function, which means that it will block until it receives the entered number of bytes or a client closes the connection after sending data. I didn't see your socket being defined and treated as non-blocking. So that part is up to curl to overcome.
Your HTTP response is wrong.
The header should look like:
"HTTP/1.1 200 OK\r\nStatus: 200 OK\r\nContent-Type: text/plain\r\n\r\n"
You may also add a header:
"Content-Length: 0"
as you aren't sending any data back except the header.
Also, if you continue using HTTP/0.9 or switch to HtTP/1.0, you should close the connection with a client after sending the data to him.
HTTP/1.1 supports opened connection, but it is usually controlled via Keep-Alive and Connection headers.
ok, -1 for me, it didn't work due to the missing '\n' character in strcpy..
I am writing a simple client program which connects to a the ip address "172.31.1.34" and sends a message. Everything works fine but I am not able to recieve any message from the server. The error says "no route to host".
My code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main()
{
struct sockaddr_in server,client;
int s1,s2,len;
int n;
char buffer[500];
strcpy(buffer,"GET http://172.31.1.34/ HTTP/1.0\n\n");
bzero((char *)&client,sizeof(client));
client.sin_port = htons(80);
client.sin_addr.s_addr = inet_addr("172.31.1.34");
client.sin_family = AF_INET;
s2 = socket(AF_INET,SOCK_DGRAM,0);
if(connect(s2,(struct sockaddr *)&client,sizeof(client)) == -1) {
perror("can't connect\n");
exit(1);
}
n = send(s2,buffer,strlen(buffer),0);
if(n < 0) {
perror("message not sent");
exit(1);
}
while(1) {
memset(buffer,0,sizeof(buffer));
n = recv(s2,buffer,500,0);
if(n < 0) {
perror("coudnot read");
exit(1);
}
buffer[n] = '\0';
printf("%s",buffer);
}
close(s2);
return 0;
}
Why are you using SOCK_DGRAM? That is for UDP packets. HTML uses TCP. You should use SOCK_STREAM
I have only briefly looked at your code, but at first glance it seems OK. However I would start with the obvious - maybe there is no route to the host....
Assuming you are on Linux or other Unix platform (including OSX), I would do the following:
ping 172.31.1.34. Note this does not guarantee the host is not available as ping may be blocked.
telnet 172.31.1.34. This should connect and you can enter your HTTP query directly
tcptraceroute 172.31.1.34 80
If all of these fail, the problem is the network, not your code.
On OSX, you can install tcptraceroute from "homebrew". On Linux use your normal package manager (or ask your system managers).
Try the code below instead:
client.sin_addr.s_addr = inet_addr("172.31.1.34");
inet_pton(AF_INET, "172.31.1.34", &client.sin_addr);
So I have a simple TCP echo server program here(IPv4) that seems to disconnect immediately after it receives a connection from a new client before the client sends a FIN packet.
Here's the echo server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_BUFFER 1024
#define PORT 4000
int main()
{
int lsock,csock, ret, in , i;
int yes = 1;
char buffer[MAX_BUFFER];
char* c;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr; // connector's address information
if((lsock = socket(AF_INET,SOCK_STREAM,0))<0){
perror("socket");
return -1;
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(lsock,(struct sockaddr*)&servaddr,sizeof(servaddr))==-1) {
perror("bind");
close(lsock);
return -1;
}
if(listen(lsock,5)==-1){
perror("listen");
close(lsock);
return -1;
}else{
printf("Server listening on port %i\n",PORT);
system("gnome-terminal");
}
while(1){
int len = sizeof(cliaddr);
bzero(&cliaddr,len);
if(csock = accept(lsock,(struct sockaddr*)&cliaddr,&len)==-1){
perror("accept");
exit(0);
}
printf("New client connected....\n");
in = recv(csock,(void*)&buffer,sizeof(buffer),0);
if(in==-1){
perror("recv");
close(csock);
exit(0);
}else if(in==0){
printf("client disconnected\n");
close(csock);
}else{
if(send(csock,(void*)buffer,sizeof(buffer),0)==-1){
perror("send");
close(csock);
}
}
}
return 0;
}
And for the the echo client application:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <linux/ioctl.h>
#define MAX_BUFFER 1024
void die(char *s)
{
perror(s);
exit(1);
}
int main()
{
int connector,flags,r;
int port;
int set = 1;
struct hostent* host;
struct in_addr in;
struct sockaddr_in rmaddr;
char sendbuffer[MAX_BUFFER];
char recvbuffer[MAX_BUFFER];
char hostname[INET_ADDRSTRLEN];
char* exit = "quit";
if((connector = socket(AF_INET,SOCK_STREAM,0))<0){
perror("socket");
return -1;
}
printf("\n");
printf("Enter the remote hostname(URL/IP4 address): ");
scanf("%s", hostname);
printf("\n");
printf("Enter the port number you wish to connect(on): ");
scanf("%u", &port);
printf("\n");
if(port==0){
printf("ERR0R: Port number must be between 1 & 65,535\n");
printf("\n");
printf("Enter the port number you wish to connect(on): ");
scanf("%u", &port);
printf("\n");
}
host = gethostbyname(hostname);
if(host==NULL){
perror("hostname");
return -1;
}
bzero(&rmaddr,sizeof(rmaddr));
rmaddr.sin_family = AF_INET;
rmaddr.sin_port = htons(port);
bcopy((char*)host->h_addr, (char*)&rmaddr.sin_addr.s_addr, host->h_length);
if(connect(connector,(struct sockaddr*)&rmaddr,sizeof(rmaddr))<0){
perror("connect");
close(connector);
return -1;
}else{
printf("\n");
printf("Connected to host: %s",hostname,"on port %u",port);
printf(" type 'quit' to disconnect\n");
printf("\n");
}
while(1){
int nbr,nbs;
nbr = 0;
printf(">");
scanf("%s",sendbuffer);
printf("\n");
if(sendbuffer==exit){
close(connector);
return 0;
}
nbs = send(connector,(void*)&sendbuffer,strlen(sendbuffer),MSG_NOSIGNAL);
printf("\n");
printf("bytes sent: %i\n",nbs);
printf("\n");
if(nbs < 0){
perror("send() failed");
close(connector);
return -1;
}
while(nbr < nbs){
nbr = recv(connector,(void*)&recvbuffer,strlen(recvbuffer),MSG_NOSIGNAL);
if(nbr < 0){
perror("recv() failed");
close(connector);
return -1;
}else if(nbr==0){
printf("recv(): connection closed prematurely");
close(connector);
return -1;
}else if(nbr > 0){
printf("bytes received: %i\n",nbr);
printf("\n");
printf(">>");
printf("%s",recvbuffer);
printf("\n");
}
}
}
EXIT:
close(connector);
return 0;
}
Now when I compile the code and then execute it, this is the output(after I connect using the echo client):
zermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7/include $ ./ES
Server listening on port 4000
New client connected....
recvmsg: Socket operation on non-socket
zermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7/include $
Now I've tried connecting the client to other hosts, like www.google.com on port 80 and the output is the same. Which is:
zermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $ ./EC
Enter the remote hostname(URL/IP4 address): www.google.com
Enter the port number you wish to connect(on): 80
Connected to host: www.google.com type 'quit' to disconnect
>hi
bytes sent: 2
recv(): connection closed prematurelyzermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $
So it's clear that the connection is getting through(that is, the server receives the SYN packet)but immediately afterwards it closes the connection. So it appears to be a problem with the recv() function but it might very well be a connect() issue. But when I try to connect to the loopback address when the server isn't running I get:
zermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $ ./EC
Enter the remote hostname(URL/IP4 address): 127.0.0.1
Enter the port number you wish to connect(on): 5000
connect: Connection refused
zermacr0yd#DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $
So I'm confoozed: Is this a server side error or a client side error? I'm thinking that the recv() function on the server side fails, the server closes the connection and shuts down, and then the client doesn't know that the server isn't running until the user on the client side tries to send a message and no bytes are received. It might very well be the client disconnecting but that doesn't look likely.
This line is wrong. It is going to evaluate to TRUE or FALSE (value 0 or 1) every time.
if (csock = accept(lsock, (struct sockaddr*) & cliaddr, &len) == -1)
{
perror("accept");
exit(0);
}
Consequently when you try a socket operation on file descriptor 0 or 1 - normally stdin and stdout - you are going to get the error that you are seeing: recvmsg: Socket operation on non-socket
Change the line to this:
if ((csock = accept(lsock, (struct sockaddr*) & cliaddr, &len)) == -1)
In your orignal server code, you had:
if(csock = accept(lsock,(struct sockaddr*)&cliaddr,&len)<0){
perror("accept");
exit(0);
}
which you have now changed to:
if(csock = accept(lsock,(struct sockaddr*)&cliaddr,&len)==-1){
perror("accept");
exit(0);
}
But the problem is the same. Here, csock is probably getting the value 0, which would correspond to the standard input, and would thus not be a socket. (I assume 0, because if it becomes 1, your server would have exited early with an accept error message from perror().) This is because the < and == operators have higher precedence that =. You can fix this by adding a set of parentheses around the assignment (I stated this clearly before Duck provided his answer), or placing the assignment before the check. Since it seems you did not actually attempt either of my suggestions until you saw Duck's answer, I will illustrate the second suggestion:
csock = accept(lsock,(struct sockaddr*)&cliaddr,&len);
if (csock == -1) {
perror("accept");
exit(0);
}
Your client test is invalid since you are connecting to an HTTP port, expecting ECHO behavior. You cannot draw any conclusions other than web servers do not accept hi as input.
Your server code is not well designed. It is a single threaded iterative server, but it does not properly clean up the existing client connection before iterating to perform another blocking accept() call. Instead, the client should handle the client connection until the connection is terminated before looping back to accept(). There are alternatives (have a separate thread handle the client connection, or use event driven loop with select()/poll()/epoll()). However, given that this seems to be a learning project, just handle one connection at a time is fine. However, you need an inner loop to completely handle the client connection before you accept() again. In pseudo-code:
while (not done)
new_conn = accept()
while (new_conn != -1)
result = read(new_conn, buf, bufsize)
switch (result)
case -1:
perror("read") /* FALLTHROUGH */
case 0:
close(new_conn)
new_conn = -1
break
default:
write(new_conn, buf, result)
break
The illustration above fixes another issue with your server, in that you are writing the complete buffer on the new connection, when instead you should only be writing out the number of bytes read, which in your case is stored in the variable in. So, instead of:
if(send(csock,(void*)buffer,sizeof(buffer),0)==-1){
Do this instead:
if(send(csock,(void*)buffer,in,0)==-1){
You had an operator precedence problem in the line that calls accept(), as noted by Duck. That accounts for 'socket operation on non-socket'.
'Connection refused' occurs at the client when the server cannot be found. It therefore has nothing to do with the server code whatsoever.
In your client you need to call perror() immediately after detecting an error, not three printf()'s later. Otherwise you corrupt errno and print the wrong error.
There is no 'premature disconnect' here. Just a disconnect, and a very misleading error message of your own devising. You're reading in a loop. Somebody has to disconnect some time. If you connect that client to a real echo server, it will echo one response and it may well then close the connection.
So in addition to following Ducks suggestion and adding a receiving loop to the server code, I realized that part of the problem with the echo_client was the following lines:
while(1){
int nbr,nbs;
nbr = 0;
When I removed the line that initialized nbr(number-of bytes received) to zero, the client does not disconnect and it actually works as I intended it to.