C Socket Programming: HTTP request not working continously - c

I am a newbie to c socket programming and c itself. I have written a small piece of code that reads raw input from another internet socket and post the data to a webserver. the received data is always numeric. however the problem seems that the http post request happens only once instead of running in a loop and the program terminates.
following is the code example
#include <sys/types.h>
#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 <netdb.h>
//define server parameters
#define WEBIP "172.16.100.2"
int main()
{
//declare variables
struct sockaddr_in my_addr,client_addr,server_addr;
struct hostent *server_host;
int true=1;
int client_socket_id,server_socket_id;
int client_id;int sin_size;
int client_bytes_received;
char send_data [1024],recv_data[1024],post_data[1024];
server_host=gethostbyname(WEBIP2);
//create a socket to listen to client
if ((client_socket_id = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Error Creating Socket");
exit(1);
}
if (setsockopt(client_socket_id,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) {
perror("Setsockopt");
exit(1);
}
//create socket to connect to webserver
if ((server_socket_id = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Error Creating Webserver Socket");
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(7070);
my_addr.sin_addr.s_addr = INADDR_ANY;
//bzero(&(my_addr.sin_zero),8);
bzero(&(server_addr.sin_zero),8);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(WEBPORT);
server_addr.sin_addr = *((struct in_addr *)server_host->h_addr);
//bind to a socket
if (bind(client_socket_id, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1) {
perror("Unable to bind");
exit(1);
}
//listen to socket
if (listen(client_socket_id, 5) == -1) {
perror("Error Listening to Socket");
exit(1);
}
printf("\n\r Waiting for client on port 7070");
fflush(stdout);
while(1)
{
sin_size = sizeof(struct sockaddr_in);
client_id = accept(client_socket_id, (struct sockaddr *)&client_addr,&sin_size);
printf("\n I got a connection from (%s , %d)",
inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
//connect to remote server
if (connect(server_socket_id, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1)
{
perror("Error Connecting to Web Server");
exit(1);
}
while(1){
//send some data to client
send(client_id,"Hello, World!",13, 0);
//receive some data from client
client_bytes_received=recv(client_id,recv_data,1024,0);
recv_data[client_bytes_received] = '\0';
//print received_data
int c_length=strlen(recv_data)+11;
printf("\n\rRecieved data (%d bytes %d words)= %s " , client_bytes_received,c_length,recv_data);
//post dta to webserver
fflush(stdout);
bzero(&post_data,1024);
sprintf(post_data,"POST /environment.php HTTP/1.1\r\n"
"Host: 172.16.100.2\r\n"
"User-Agent: C Example Client\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: %d\r\n\r\n"
"track_data=%s",c_length,recv_data);
write(server_socket_id,post_data,strlen(post_data)+1);
bzero(&recv_data,1024);
while((client_bytes_received=read(server_socket_id,recv_data,1024))>0){
recv_data[client_bytes_received] = '\0';
if (fputs(recv_data,stdout)==EOF)
perror("web server read_error");
}
//print received_data
printf("\n\rRecieved data from webserver (%d)= %s " , client_bytes_received,recv_data);
//
bzero(&recv_data,1024);
fflush(stdout);
}
}
close(client_id);
close(client_socket_id);
return 0;
}

I have not done socket programming for years, so please bear with me. Do you need to connect, process, and then disconnect? That's the first thing that came to mind reading your code.

I am surprised this program works. You have created blocking sockets, unless you are working on a non-POSIX compliant OS. The accept call should have never returned. If accept is returning it means that your server socket is not able to go into the wait mode. Hence whatever you are seeing is most likely because of an error.
SO_NONBLOCK is the socket option you can use for creating non blocking sockets.
Since you are using the same routine for both client and server you should use select in the socket loop.

Related

socket binding failed (address already in use, even with SO_REUSEADDR)

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?

Socket Programming in C: When client exit server, the server is crashed

I run a socket programming code for communication of multiple clients with one server. Everything happens properly but when I ctrl C to exit one of client, the server does not show as I expected. Below is the code:
Client.c
#include <stdio.h>
#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>
#define PORT 4444
int main(){
int clientSocket, ret;
struct sockaddr_in serverAddr;
char buffer[1024];
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if(clientSocket < 0){
printf("[-]Error in connection.\n");
exit(1);
}
printf("[+]Client Socket is created.\n");
memset(&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if(ret < 0){
printf("[-]Error in connection.\n");
exit(1);
}
printf("[+]Connected to Server.\n");
while(1){
printf("Client: \t");
scanf("%s", &buffer[0]);
send(clientSocket, buffer, strlen(buffer), 0);
if(strcmp(buffer, ":exit") == 0){
close(clientSocket);
printf("[-]Disconnected from server.\n");
exit(1);
}
if(recv(clientSocket, buffer, 1024, 0) < 0){
printf("[-]Error in receiving data.\n");
}else{
printf("Server: \t%s\n", buffer);
}
}
return 0;
}
Server.c
#include <stdio.h>
#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>
#define PORT 4444
int main(){
int sockfd, ret;
struct sockaddr_in serverAddr;
int newSocket;
struct sockaddr_in newAddr;
socklen_t addr_size;
char buffer[1024];
pid_t childpid;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
printf("[-]Error in connection.\n");
exit(1);
}
printf("[+]Server Socket is created.\n");
memset(&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if(ret < 0){
printf("[-]Error in binding.\n");
exit(1);
}
printf("[+]Bind to port %d\n", 4444);
if(listen(sockfd, 10) == 0){
printf("[+]Listening....\n");
}else{
printf("[-]Error in binding.\n");
}
while(1){
newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size);
if(newSocket < 0){
exit(1);
}
printf("Connection accepted from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
if((childpid = fork()) == 0){
close(sockfd);
while(1){
recv(newSocket, buffer, 1024, 0);
if(strcmp(buffer, ":exit") == 0){
printf("Disconnected from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
break;
}else{
printf("Client: %s\n", buffer);
send(newSocket, buffer, strlen(buffer), 0);
bzero(buffer, sizeof(buffer));
}
}
}
}
close(newSocket);
return 0;
}
When I press ctrl C to exit the client. On the server side, it shows:
Client:
Client:
Client:
Client:
and it's seem to loop "Client:" forever instead of showing message of printf"Disconnected from..." and continue to work with other clients as I expected. I look at this code from on youtube, they can run it properly in the video but I do not know why when I download this code and run on my computer, it gets that problem. Can anyone help me to fix that problem so that the server can print the message "Disconnection...". Thank you.
When I press ctrl C to exit the client. On the server side, it shows:
Client:
Client:
Client:
Client:
and it's seem to loop "Client:" forever instead of showing message of
printf"Disconnected from..." and continue to work with other clients
as I expected.
Your code prints the disconnection message and exits the loop only if it receives an ":exit" message from the client. If you kill the client with a Ctrl-C, then it terminates without sending any such message.
Robust server code would check the return value of the recv() call, which would return -1 to signal an error. Your server ignores that and just tries to read again, and again, and again. Although you cannot rely on getting an error in every scenario where the client goes away, the fact that your server keeps printing "Client:" indicates that you are getting one in this case.
I look at this code from on youtube, they can run it properly in the
video but I do not know why when I download this code and run on my
computer, it gets that problem.
Either what they demonstrated in the video was different from the code you've presented (maybe the video was deceptive about that), or they exited the client by typing an ":exit" command, not just killing the client.
It sounds like your client isn't properly closing the connection. If you're using Ctrl C to stop the client, then you are killing the client program and not breaking the loop. If you want to stop the client that way, you should handle SIGINT and close the socket connection.

How to emulate PUB/SUB with unix sockets (AF_UNIX, SOCK_DGRAM)?

I am struggling to make this simple communication working.
I made it with zmq in less than five minutes.
Doing it with UNIX sockets is a pain (obviously because of my lack of confidence).
This is the server:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "streamsocket.h"
char *socket_path = "/tmp/stream";
int socket_fd=0;
struct sockaddr_un addr;
int main(){
socket_setup();
while(1){
socket_sendstr("a");
sleep(1);
}
}
void socket_setup(){
int rc;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, socket_path);
if ( (socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
rc=bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr));
if(rc<0){
perror("bind error");
exit(-2);
}
}
int socket_sendstr(char* buffer) {
int len=strlen(buffer);
// corrected after suggestion in answer below (rc->len)
// int rc=write(socket_fd, buffer, rc);
int rc=write(socket_fd, buffer, len);
if (rc != len) {
if (rc > 0) fprintf(stderr,"partial write");
else {
perror("write error");
//exit(-1);
}
}
}
And this is the client:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
char * server_filename = "/tmp/stream";
char * client_filename = "/tmp/stream-client";
struct sockaddr_un server_addr;
struct sockaddr_un client_addr;
int rc;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, server_filename, 104);
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sun_family = AF_UNIX;
strncpy(client_addr.sun_path, client_filename, 104);
// get socket
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
// bind client to client_filename
rc = bind(sockfd, (struct sockaddr *) &client_addr, sizeof(client_addr));
if(rc==-1) perror("bind error");
// connect client to server_filename
rc = connect(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr));
if(rc==-1) perror("connect error");
char buf[1024];
int bytes=0;
while(bytes = read(sockfd, buf, sizeof(buf))){
printf("%s\n",buf);
}
close(sockfd);
}
What I am doing wrong?
At the moment the client does not print anything.
EDIT1: correct wrong "rc" in server write( , ,rc) to write( , ,len)
EDIT2: as client does not work socat either:
socat UNIX-CLIENT:/tmp/stream -
so I think that the problem could be in the server.
int len=strlen(buffer);
int rc=write(socket_fd, buffer, rc);
Doesn't write expects to get as third parameter the length ;
You misunderstand how datagram sockets work, and this is not local to Unix sockets -- you'd have the same problem with UDP.
Datagram sockets are entirely connectionless. A connect() on a datagram socket doesn't actually make any connection, it just sets a default destination for packets sent on the socket. It's just for convenience so that you can use send instead of sendto in the case where you always send to the same address.
You can make the server reply to a particular client if the client sends a packet to the server first, in which case you can reply, using sendto, to the same address that you got from recvfrom. If you actually want to make a connection between the client and the server, however, you'll need to use either a stream socket or a seqpacket socket instead. In that case, you will also need to ensure you're doing the proper listen/accept sequence in the server as well.
In fact, I would, if anything, be surprised if your server doesn't print errors when it tries to send. It should be saying write error: Transport endpoint is not connected.

Unable to connect with multiple client with my socket server program

My socket server program is mentioned below. It works fine with the single client but when I try to connect it with another client at the same time, I am unable to connect. But I have defined MAX_CLIENTS in my program as 2 but still why I am unable to connect with multiple clients? What is the correct process to connect with multiple client? Will I be able to connect with multiple client by modifying this code? Any possible fix?
Socket Server Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <error.h>
#include <strings.h>
#include <unistd.h>
#include <arpa/inet.h>
#define ERROR -1
#define MAX_CLIENTS 2
#define MAX_DATA 1024
main (int argc, char **argv){
struct sockaddr_in server;
struct sockaddr_in client;
int sock;
int new;
int sockaddr_len = sizeof (struct sockaddr_in);
int data_len;
char data [MAX_DATA];
if ((sock = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("socket: ");
exit (-1);
}
printf("after socket");
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = INADDR_ANY;
bzero (&server.sin_zero, 8);
printf("after server");
if ((bind (sock, (struct sockaddr*)&server, sockaddr_len)) == -1)
{
perror ("bind");
exit (-1);
}
printf("after bind");
if ((listen(sock, MAX_CLIENTS)) == ERROR)
{
perror ("listen");
exit (-1);
}
printf("after listen");
while(1)
{
if ((new = accept(sock, (struct sockaddr*)&client, &sockaddr_len)) == ERROR)
{
perror ("accept");
exit (-1);
}
printf("after new");
printf("New client connected from port no %d and IP %s\n",ntohs(client.sin_port), inet_ntoa(client.sin_addr));
data_len = 1;
while (data_len)
{
data_len = recv (new, data, MAX_DATA, 0);
if (data_len)
{
send (new, data, data_len, 0) ;
data [data_len]='\0';
printf("Sent mesg: %s", data);
}
printf("after datalen");
}
printf("Client Disconnected\n");
close(new);
}
printf("after close new");
close (sock);
}
Your program is single-threaded, and only does one thing at a time. When you have accepted a socket connection from a client (in your outer while loop) you start communicating with that client (in your inner while loop), and you don't get back to the accept call until the first client has disconnected.
Either use threads, with one thread that waits for new connections and one additional thread for each client, waiting for input from that client, or use the select call, which lets you wait for input simultaneously from several different sources.

Passing multiple messages from client -> server and server -> client sockets in C

Could someone help identify why my server cannot accept more than one message from the client?
I am attempting to have the flow be like the following:
1. Client sends size of message to server
2. Server receives the size and sends a response back. In this case 0.
3. Client checks response and then writes message to server.
4. Server reads message and prints it out.
The problem I am getting is that the accept() at step 4 is never unblocking.
CLIENT
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char *argv[])
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s_address;
s_address.sin_family = AF_INET;
s_address.sin_port = htons(51717);
s_address.sin_addr.s_addr = INADDR_ANY;
if (connect(sock, (struct sockaddr *) &s_address, sizeof(s_address)) < 0) {
printf("ERROR: Cannot connect()\n");
exit(0);
}
char *org_msg = "Hello";
printf("Writing size of Hello\n");
char msg1[1];
msg1[0] = sizeof(org_msg);
write(sock, msg1, sizeof(msg1));
printf("Waiting for response from server\n");
struct sockaddr_in c_address;
socklen_t c_length = sizeof(c_address);
int new_sock = accept(sock, (struct sockaddr *) &c_address, &c_length);
printf("Reading response from server\n");
char stat[1];
read(new_sock, stat, 1);
if (atoi(stat) == 0) {
printf("Writing Hello to server\n");
write(sock, org_msg, sizeof(org_msg));
}
close(sock);
close(new_sock);
}
SERVER
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char *argv[])
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s_address;
s_address.sin_family = AF_INET;
s_address.sin_port = htons(51717);
s_address.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *) &s_address, sizeof(s_address)) < 0) {
printf("ERROR: Cannot bind()\n");
exit(0);
}
listen(sock, 3);
printf("Waiting for client message\n");
struct sockaddr_in c_address;
socklen_t c_length = sizeof(c_address);
int new_sock = accept(sock, (struct sockaddr *) &c_address, &c_length);
printf("Reading client message\n");
char msg[1];
read(new_sock, msg, 1);
printf("Writing response to client\n");
char stat[1];
stat[0] = '0';
write(new_sock, stat, sizeof(stat));
printf("Waiting for client message\n");
int new_sock2 = accept(sock, (struct sockaddr *) &c_address, &c_length);
printf("Reading client message\n");
char msg2[atoi(msg)];
read(new_sock2, msg2, sizeof(msg2));
printf("MESSAGE: %s\n", msg2);
close(sock);
close(new_sock);
close(new_sock2);
}
You should not call accept() on an already-connected socket. Once you have a connected socket in the server (the socket returned by accept()) you should just keep reading and writing that socket until the connection is closed. The steps for the server should be similar to:
listen_socket = socket(...);
listen(listen_socket, ...);
connected_socket = accept(listen_socket, ...);
read(connected_socket, ...)
write(connected_socket, ...)
read(connected_socket, ...)
write(connected_socket, ...)
...
Similarly the client should just keep reading and writing the socket once it has been connected successfully - the steps for the client should be:
connected_socket = socket(...);
connect(connected_socket, ...);
write(connected_socket, ...);
read(connected_socket, ...);
write(connected_socket, ...);
read(connected_socket, ...);
...
INADDR_ANY works in the server but your client needs to specify what host it's connecting to.
If both are on the same machine, just use 127.0.0.1 or localhost (you'll have to do a transform so that it's the right format)
More information here, but a short answer would be
#define INADDR_LOOPBACK 0x7f000001
and then s_address.sin_addr.s_addr = htonl (INADDR_LOOPBACK)
On the client you try to accept a new connection with the socket you previously connected to the server, which will be bound to a system-chosen port number. The server never tries to connect to the client, so the accept call on the client never returns (actually it may return but with an error, because you never call listen on that socket).
Why not just perform step 3 with the same socket used in the previous steps? If for some reason you do need a new socket, you should create a new socket in the client instead of reusing the previous socket (or call close on the previous socket and then call connect on it again).
BTW if all you need is IPC, sockets are a really bad way to do it. I suggest something like Java RMI.

Resources