Reputation: 170
Ok so guys i've been working like 2 days straight, searching for bugs and looking for last years solutions and other software but found
My problem is that i need to program a fairly easy server client application in which both take responses and reply to them. I wrote smaller programs to just demonstrate my problem.
And before you complain about the lack of completeness with send and recv to be checked not be < 0. I know that i gotta check that.
common.h is just a header for all the inputs and static variables.
// guard block:
#ifndef COMMON_H
#define COMMON_H
// default hostname and port:
#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT "1280"
#include <stdarg.h>
#include <ctype.h>
// IO, C standard library, POSIX API, data types:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>
// Sockets, TCP, ... :
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
// Assertions, errors, signals:
#include <assert.h>
#include <errno.h>
#include <signal.h>
static struct addrinfo *ai = NULL; // stores address information
static int sockfd = -1; // socket file descriptor
static int connfd = -1; // connection file descriptor
void terminate(int sig);
void init_signal_handler(void);
void free_ressources(void);
void error(char* format, ...);
void terminate(int sig) {
error("Caught signal %d. Terminating...\n",sig);
}
void init_signal_handler(void) {
struct sigaction sa;
sa.sa_handler = terminate;
if (-1 == sigemptyset(&(sa.sa_mask))) {
error("sigemptyset()");
}
if (-1 == sigaction(SIGINT, &sa, NULL)) {
error("sigaction()");
}
if (-1 == sigaction(SIGTERM, &sa, NULL)) {
error("sigaction()");
}
}
void error(char *format, ...) {
va_list arg;
va_start (arg, format);
(void) vfprintf (stderr, format, arg);
va_end (arg);
free_ressources();
exit(EXIT_FAILURE);
}
void free_ressources(void) {
(void) printf("Freeing all ressources...\n");
if(sockfd != -1) close(sockfd);
if(connfd != -1) close(connfd);
freeaddrinfo(ai);
}
#endif // COMMON_H
So here is the client
#include "common.h"
static char *port = DEFAULT_PORT;
static char *host = DEFAULT_HOST;
int main(int argc, char *argv[]) {
int s;
struct addrinfo hints, *rp;
memset(&ai, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(host, port, &hints, &ai);
if(s != 0) error("Couldn't get address info...\n");
for (rp=ai; rp != NULL; rp=rp->ai_next) {
sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sockfd == -1) continue;
if((connfd = connect(sockfd, rp->ai_addr, rp->ai_addrlen)) != -1) break;
close(sockfd);
}
if(rp == NULL) error("Couldn't connect...\n");
uint16_t msg = 0xF0F0;
uint8_t msg_r = 0x00;
for(int i = 0; i < 10; ++i) {
(void) fprintf(stdout, "Sending message %#X\n", msg);
send(sockfd, &msg, 2, MSG_CONFIRM);
recv(connfd, &msg_r, 1, MSG_CONFIRM);
(void) fprintf(stdout, "Recieved from Server %#X\n", msg_r);
msg+=1;
}
free_ressources();
}
And here is the server
#include "common.h"
static char *port = DEFAULT_PORT;
int main(int argc, char *argv[]) {
struct addrinfo hints;
memset(&ai, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
int res = getaddrinfo(NULL, port, &hints, &ai);
if(res != 0) error("Failed to get addr info: %s\n", gai_strerror(res));
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(sockfd == -1) error("Couldn't create a socket\n");
int val = 1;
res = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
if(res == -1) error("Socket options couldn't be set\n");
res = bind(sockfd, ai->ai_addr, ai->ai_addrlen);
if(res == -1) error("Socket binding failed\n");
res = listen(sockfd, 1);
if(res == -1) error("Listener setup failed\n");
connfd = accept(sockfd, NULL, NULL);
if(connfd == -1) error("Connect failed\n");
uint8_t msg_s = 0x00;
uint16_t msg = 0x0000;
for(int i = 0; i < 10; ++i) {
msg_s+=1;
recv(connfd, &msg, 2, MSG_CONFIRM);
(void) fprintf(stdout, "Recieved from Client %#X\n", msg);
(void) fprintf(stdout, "Sending %#X\n", msg_s);
send(sockfd, &msg_s, 1, MSG_CONFIRM);
}
free_ressources();
}
Ok so i have several problems with this.
If i do a server client application in one direction, like only client sends and only server recieves, everything goes smooth and expected as always. However things change when i mix it up like here. I understand that TCP is a stream protocol without fixed "package" amounts, but i also can understand how to implement that with just needing 2 bytes max. I might try to just recieve 1 byte at a time and do that in a loop if i need 2, but why though? Why is everything fine at onelane mode and goes hell in mixed?
I tried to use recv and send accordingly to its man pages so use them with the socket. However i don't know why, but whenever i try to use recv with the sock_fd it just won't work, but conn_fd on the otherside does. But i see everywhere that i clearly should use sock_fd.
This is my output when i mix up the recv and send
OUTPUT FROM SERVER
Recieved from Client 0XF0F0
Sending 0X1
OUTPUT FROM CLIENT
Sending message 0XF0F0
Recieved from Server 0
Sending message 0XF0F1
Recieved from Server 0
Sending message 0XF0F2
Recieved from Server 0
Sending message 0XF0F3
Recieved from Server 0
Sending message 0XF0F4
Recieved from Server 0
Sending message 0XF0F5
Recieved from Server 0
Sending message 0XF0F6
Recieved from Server 0
Sending message 0XF0F7
Recieved from Server 0
Sending message 0XF0F8
Recieved from Server 0
Sending message 0XF0F9
Recieved from Server 0
Freeing all ressources...
So in conclusion, i know maybe it's a stupid and simple question, but why is it like that? Why does the server crash at sending the very first message, whereas the client seams to throw out his messages into the void.
Thanks for any answers in advance, i really need to solve this.
Upvotes: 0
Views: 717
Reputation: 170
Ok wow thanks guys. I was so desperate on solving this problem. Thanks for all answers and especially to @Stargateur and @user3629249.
Ok so there are 2 things i needed to be made clear of and thankfully with you guys i get it now.
On the Server side the descriptor to the client is given by accept, so i need to use in my case connfd.
So here below i post my solution to this problem, and again thanks guys! You made my day! For sake of simplicity the header file isn't changed, however there are still somethings left in this code also. If you use something similar please error check on everything, like the recv and send methods and please read the comments from Stargateur and user3629249, it will help you to understand why my code failed and now works.
Makefile
CC = /usr/bin/gcc
CFLAGS = -std=c99 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -g -c
SERVER = server
CLIENT = client
all: $(SERVER).c $(CLIENT).c clean compile compile2
compile: $(SERVER).c $(CLIENT).c
gcc $(CFLAGS) $(SERVER).c
gcc $(CFLAGS) $(CLIENT).c
compile2: $(SERVER).o $(CLIENT).o
gcc $(SERVER).o -o $(SERVER)
gcc $(CLIENT).o -o $(CLIENT)
clean: $(SERVER) $(SERVER).o $(CLIENT) $(CLIENT).o
rm $(SERVER) $(SERVER).o
rm $(CLIENT) $(CLIENT).o
Client
#include "common.h"
static char *port = DEFAULT_PORT;
static char *host = DEFAULT_HOST;
int main() {
int s;
struct addrinfo hints, *rp;
memset(&ai, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(host, port, &hints, &ai);
if(s != 0) error("Couldn't get address info...\n");
for (rp=ai; rp != NULL; rp=rp->ai_next) {
sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sockfd == -1) continue;
if((connfd = connect(sockfd, rp->ai_addr, rp->ai_addrlen)) != -1) break;
close(sockfd);
}
if(rp == NULL) error("Couldn't connect...\n");
uint8_t msg = 0x00;
for(int i = 0; i < 10; ++i) {
msg=(uint8_t)((int)msg+1);
(void) fprintf(stdout, "Sending message %#X\n", msg);
send(sockfd, &msg, 1, MSG_CONFIRM);
recv(sockfd, &msg, 1, MSG_CONFIRM);
(void) fprintf(stdout, "Recieved from Server %#X\n", msg);
}
free_ressources();
}
Server
#include "common.h"
static char *port = DEFAULT_PORT;
uint16_t read_from_client();
int main() {
struct addrinfo hints;
memset(&ai, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
int res = getaddrinfo(NULL, port, &hints, &ai);
if(res != 0) error("Failed to get addr info: %s\n", gai_strerror(res));
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(sockfd == -1) error("Couldn't create a socket\n");
int val = 1;
res = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
if(res == -1) error("Socket options couldn't be set\n");
res = bind(sockfd, ai->ai_addr, ai->ai_addrlen);
if(res == -1) error("Socket binding failed\n");
res = listen(sockfd, 1);
if(res == -1) error("Listener setup failed\n");
connfd = accept(sockfd, NULL, NULL);
if(connfd == -1) error("Server Accept failed\n");
uint8_t msg = 0x00;
for(int i = 0; i < 10; ++i) {
recv(connfd, &msg, 1, MSG_CONFIRM);
(void) fprintf(stdout, "Recieved from Client %#X\n", msg);
msg = (uint8_t) ((int)msg + 1);
(void) fprintf(stdout, "Sending %#X\n", msg);
send(connfd, &msg, 1, MSG_CONFIRM);
}
free_ressources();
}
So the output is as expected. From ./server
./server
Recieved from Client 0X1
Sending 0X2
Recieved from Client 0X3
Sending 0X4
Recieved from Client 0X5
Sending 0X6
Recieved from Client 0X7
Sending 0X8
Recieved from Client 0X9
Sending 0XA
Recieved from Client 0XB
Sending 0XC
Recieved from Client 0XD
Sending 0XE
Recieved from Client 0XF
Sending 0X10
Recieved from Client 0X11
Sending 0X12
Recieved from Client 0X13
Sending 0X14
Freeing all ressources...
From ./client
./client
Sending message 0X1
Recieved from Server 0X2
Sending message 0X3
Recieved from Server 0X4
Sending message 0X5
Recieved from Server 0X6
Sending message 0X7
Recieved from Server 0X8
Sending message 0X9
Recieved from Server 0XA
Sending message 0XB
Recieved from Server 0XC
Sending message 0XD
Recieved from Server 0XE
Sending message 0XF
Recieved from Server 0X10
Sending message 0X11
Recieved from Server 0X12
Sending message 0X13
Recieved from Server 0X14
Freeing all ressources...
Upvotes: 0
Reputation: 26767
You have some minors issue and some big issue:
Small:
ai_protocol
in hints
, but it's require by getaddrinfo()
when hints
is not NULL
connect()
as a file descriptor but it's a error code number. You must use the file descriptor return by socket()
in a client, or by accept()
in a server.send()
in the server. You SHOULD not send data on the file descriptor that handle connection in a SOCK_STREAM
socket type.getaddrinfo()
return a list, you should iterate on it, but you assume that there is always one result, but they could be zero or more than one.hints
is initialized, you invoke undefined behavior with memset()
because sizeof(struct addrinfo) > sizeof(struct addrinfo *)
so you are out of bound when you write zero on ai
(GLOBAL... GLOBAL EVERYWHERE)Big:
// server and client
struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_PASSIVE,
.ai_protocol = IPPROTO_TCP,
};
// server
if (send(connfd, &msg_s, 1, MSG_CONFIRM) == -1) {
// error
}
// client
if (recv(sockfd, &msg_r, 1, MSG_CONFIRM) == -1) {
// error
}
Upvotes: 1