Related
I wrote a code about sockets and I cannot prevent the server to close when the client sends a message or when the client do a CTRL + C
The server goes off.
Server.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#define PORT 8888
#define BACKLOG 10
#define LOOP(i, n) for((i) = 0; (i) < (n); (i)++)
#define BUFFSIZE 6500
int create_fd( struct sockaddr_in *server );
int bind_fd ( struct sockaddr_in *server, int servSocket );
int list_fd( int servSocket );
int accept_fd( struct sockaddr_in *server, int servSocket );
int select_fd ( fd_set *readfds, int max_sd );
ssize_t send_fd( int new_fd, const char *const msg );
int main( void ){
const char msg[BUFFSIZE] = "Server is On\n";
char recive[BUFFSIZE];
int servSocket ,clientSocket ,i ,sd;
int client_socket_max[30] = { 0 } , max_clients = 30;
int max_sd;
ssize_t valread;
struct sockaddr_in server;
for (i = 0; i < max_clients; i++)
{
client_socket_max[i] = 0;
}
//set of socket descriptors
fd_set readfds;
size_t addr_size = sizeof(server);
//create
servSocket = create_fd( &server );
//bind the socket to localhost port 8888
bind_fd(&server, servSocket );
//listen the socket to localhost port 8888
printf("\tServer is On\nListener on port %d \n", PORT);
list_fd( servSocket );
//accept the incoming connection
printf( "\n\tWaiting for connections ...\n" );
while(1){
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(servSocket, &readfds);
max_sd = servSocket;
//add child sockets to set
LOOP( i, max_clients ){
//socket descriptor
sd = client_socket_max[i];
//if valid socket descriptor then add to read list
if(sd > 0){
FD_SET( sd , &readfds);
}
//highest file descriptor number, need it for the select function
if(sd > max_sd){
max_sd = sd;
}
}
//wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
select_fd( &readfds, max_sd );
//select( max_sd + 1 , &readfds , NULL , NULL , NULL);
//If something happened on the master socket , then its an incoming connection
if ( FD_ISSET( servSocket, &readfds ) ){
clientSocket = accept_fd( &server, servSocket );
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d \n" , clientSocket , inet_ntoa(server.sin_addr) , ntohs(server.sin_port));
//send new connection greeting msg
send_fd( clientSocket, msg );
/*if( send(clientSocket, msg, strlen(msg), 0) != (long int)strlen(msg) ){
perror("send");
}*/
puts("Welcome msg sent successfully");
//add new socket to array of sockets
LOOP( i, max_clients ){
//if position is empty
if( client_socket_max[i] == 0 ){
client_socket_max[i] = clientSocket;
printf("Adding to list of sockets as %d\n" , i);
break;
}
}
}
//else its some IO operation on some other socket :)
LOOP( i, max_clients ){
sd = client_socket_max[i];
if (FD_ISSET( sd , &readfds)){
//Check if it was for closing , and also read the incoming msg
if (( valread = read( sd , recive, 1024)) == 0){
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&server , (socklen_t*)&addr_size);
printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(server.sin_addr) , ntohs(server.sin_port));
//Close the socket and mark as 0 in list for reuse
close( sd );
client_socket_max[i] = 0;
}else{//Echo back the msg that came in
//set the string terminating NULL byte on the end of the data read
recive[valread] = '\0';
send(sd , recive , strlen(recive) , 0 );
}
}
}
}
close( servSocket );
}
int create_fd( struct sockaddr_in *server ){
int opt = 1;
int servSocket = socket(AF_INET , SOCK_STREAM , 0);
if (servSocket == -1 ){
printf("Error, socket()\n");
fprintf(stderr, "socket: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}
//set master socket to allow multiple connections , this is just a good habit, it will work without this
if( setsockopt(servSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 ){
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
server->sin_family = AF_INET;
server->sin_addr.s_addr = INADDR_ANY;
server->sin_port = htons( PORT );
//printf("socket() \tOK\n");
return servSocket;
}
int bind_fd ( struct sockaddr_in *server, int servSocket ){
int bindfd = bind( servSocket, (struct sockaddr *)server, sizeof(*server) );
if (bindfd == -1 ){
printf("Error, bind(), check line 34\n");
fprintf(stderr, "bind: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}else{
//printf("bind() \t\tOK\n");
return bindfd;
}
}
int list_fd( int servSocket ){
int listfd = listen(servSocket, BACKLOG);
if (listfd == -1 ){
printf("Error, listen()\n");
fprintf(stderr, "listen: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}else{
//printf("listen() \tOK\n");
return listfd;
}
}
int accept_fd( struct sockaddr_in *server, int servSocket ){
int new_fd;
socklen_t addr_size = sizeof( server );
new_fd = accept(servSocket, (struct sockaddr *)server, (socklen_t*)&addr_size);
if (new_fd == -1 ){
printf("Error, accept()\n");
fprintf(stderr, "accept: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}else{
//printf("accept() \tOK\n");
return new_fd;
}
}
int select_fd ( fd_set *readfds, int max_sd ){
int activity = select( max_sd + 1 , readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR)){
printf("select error");
exit ( EXIT_FAILURE );
}else{
return activity;
}
}
ssize_t send_fd( int new_fd, const char *const msg ){
size_t len = strlen(msg);
ssize_t sendfd;
sendfd = send( new_fd, msg, len, 0 );
if (sendfd == -1 ){
printf("Error, write()\n");
fprintf(stderr, "recv: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}else{
printf("write() \tOK\n");
printf("Client sent:\t%s", msg );
return sendfd;
}
}
Client.c:
#include <stdio.h>
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#define PORT 8888
#define BUFFSIZE 6500
int create_fd( struct sockaddr_in server );
int connect_fd( const int servSocket, struct sockaddr_in *server );
int opt = 1;
int main ( void ){
struct sockaddr_in server;
char recivemsg[BUFFSIZE];
char sendmsg[BUFFSIZE];
memset( recivemsg, 0, sizeof(*recivemsg) );
memset( sendmsg, 0, sizeof(*sendmsg) );
int servSocket = socket(AF_INET , SOCK_STREAM , 0);
if (servSocket == -1 ){
printf("Error, socket()\n");
fprintf(stderr, "socket: %s (%d)\n", strerror(errno), errno);
exit ( EXIT_FAILURE );
}
//set master socket to allow multiple connections , this is just a good habit, it will work without this
if( setsockopt(servSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 ){
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( PORT );
if ( ( connect( servSocket, ( struct sockaddr* )&server, sizeof( server ) ) ) < 0 ){
printf("Error, connect()\n");
fprintf(stderr, "connect: %s (%d)\n", strerror(errno), errno);
exit( EXIT_FAILURE );
}
if ( recv( servSocket, recivemsg, sizeof ( recivemsg ), 0 ) < 0 ){
printf("Error, recv()\n");
fprintf(stderr, "recv: %s (%d)\n", strerror(errno), errno);
exit( EXIT_FAILURE );
}
printf("Send a msg to the Server:> ");
fgets(sendmsg, BUFFSIZE, stdin );
if ( send( servSocket, sendmsg, sizeof ( sendmsg ), 0 ) < 0 ){
printf("Error, send()\n");
fprintf(stderr, "send: %s (%d)\n", strerror(errno), errno);
exit( EXIT_FAILURE );
}
close( servSocket );
}
There are a few problems with the code that together could lead to premature exits from your server program.
The most important is that you don't check for errors from either your read or send calls.
If the read call fails it will return -1 which you don't check for (and which will lead to you using -1 as index into your array receive, which is out of bounds and lead to undefined behavior). That will in turn lead to you calling send with a broken connection, which will cause the operating system to send a SIGPIPE signal to your process.
The default behavior of SIGPIPE is to terminate the process.
The usual way to handle this is to ignore the SIGPIPE signal, as then send would return with an error (it returns -1 with errno set to EPIPE) that you should handle.
The common way to handle errors (from either read or send) is to simply close your end of the connection. That's because most errors are simply not recoverable.
I am new to the topic of network communication, but would like to set up an UDP server client connection, with one participant continuously broadcasting data whether anyone is listening in on it or not and two participants that start receiving and storing these information whenever they are ready to do so (It's fine if they miss what has been sent before that point). The idea is that there is no other communication than one participant sending data (fire and forget) and two participants receiving them, without any form of feedback to the sending part. For now I would like to get it running on my local host, but would like to use it on a network.
I have been looking into a solution for quite some time now and decided to have a client broadcast the file stream continuously on two separate ports so, so that the receiving two servers can bind to a port respectively without blocking each other (If there is a better way, I am open for suggestions).
So far I have been able to set up this kind of communication with one client and one server, following these instructions. However, when I try to set up a second socket in my client executable, I always receive the error message Invalid argument once I reach the sendto() part.
Seeing as I have not been able to find a solution myself, yet I would like to ask for some help.
My code so far consists of the
Client:
/** set up socket_1 properties */
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; // use my IP
/** Read address information of incoming connection */
int status;
struct addrinfo *servinfo;
if ((status = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 1;
}
/** loop through all the results and bind to the first we can */
int sockfd;
struct addrinfo *p;
for ( p = servinfo; p != NULL; p = p->ai_next ) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
break;
}
if (p == NULL) {
printf("[ERROR]: Failed to bind broadcaster socket 1: %s.\n", strerror(errno) );
return 2;
}
/** set up socket_2 */
// ( reuse socket_1 hints and change the port number )
/** Read address information of incoming connection */
int status_2;
struct addrinfo *servinfo_2;
if ((status_2 = getaddrinfo(NULL, MYPORT_2, &hints, &servinfo_2)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status_2));
return 1;
}
/** loop through all the results and bind to the first we can */
int sockfd_2;
struct addrinfo *p_2;
for ( p_2 = servinfo_2; p_2 != NULL; p_2 = p_2->ai_next ) {
if ((sockfd_2 = socket(p_2->ai_family, p_2->ai_socktype, p_2->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
break;
}
if (p_2 == NULL) {
printf("[ERROR]: Failed to bind broadcaster socket 2: %s.\n", strerror(errno) );
return 2;
}
...
some file read/write related stuff
...
while ( /* some condition */ )
{
if ( ( readBytes = pread( fd, buf, BUFFER_SIZE, offset ) ) == -1 ){
printf("[ERROR]: %s.\n", strerror(errno) );
free( buf );
close( fd );
close( sockfd );
exit(1);
}
// the next line is generating the error message
if ( ( numbytes = sendto( sockfd, buf, readBytes, 0, p->ai_addr, p->ai_addrlen ) ) == -1 )
{
perror("sender_1: sendo.\n");
free( buf );
close( fd );
close( sockfd );
exit(1);
}
if ( ( numbytes = sendto( sockfd_2, buf, readBytes, 0, p_2->ai_addr, p_2->ai_addrlen ) ) == -1 )
{
perror("sender_2: sendo.\n");
free( buf );
close( fd );
close( sockfd_2 );
exit(1);
}
}
.
.
.
free( buf );
freeaddrinfo(servinfo);
freeaddrinfo(servinfo_2);
printf( "Broadcasting complete.\n" );
/** Clean what is not necessary anymore */
close( fd );
close( sockfd );
return 0;
}
I tried to add the reuse port and IP functionality to make sure that there is nothing blocking the setup of the new socket, but this did not solve my problem
My server side seems to work fine, but just in case I will post it here, too:
int main(int argc, char **argv)
{
if (argc < 2){
printf("Please provide image Name ID.\n");
exit(1);
}
struct addrinfo hints;
struct addrinfo *servinfo = NULL; // will point to getaddrinfo() results
memset(&hints, 0, sizeof hints); // make sure struct is empty
hints.ai_family = AF_UNSPEC; // don't care if IPv4 or IPv6
hints.ai_socktype = SOCK_DGRAM; // Use UDP protocol
hints.ai_flags = AI_PASSIVE;
int res;
if ((res = getaddrinfo( NULL, argv[1]/* SERVERPORT*/, &hints, &servinfo )) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(res));
return 1;
}
/** Get socket file descriptor */
int sockfd;
struct addrinfo *p = NULL;
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
/** Allow the reuse of an IP */
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
exit(1);
}
/** Allow the reuse of a socket */
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
exit(1);
}
/** Bind found socket to desired port */
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
printf("[ERROR]: Failed to bind socket to desired port: %s.\n", strerror( errno ) );
continue;
}
break;
}
struct timeval read_timeout;
read_timeout.tv_sec = 30;
read_timeout.tv_usec = 500;
if ( setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof read_timeout) < 0 ){
printf( "[ERROR]: %s.\n", strerror(errno) );
}
...
some file read/write stuff
...
while ( ( numbytes = recvfrom(sockfd, buf, BUFFER_SIZE, 0, (struct sockaddr *)&their_addr, &addr_len ) ) != -1)
{
.
.
.
}
printf("Done broadcasting.\n");
freeaddrinfo(servinfo);
close(sockfd);
return 0;
}
It would be much appreciated if anybody could provide me some help or point me into the right direction where to look for a solution.
Best regards
I am making an assignment in which a server fork's multiple children, one for each sensor connected to the server (and each child then has a tcp connection to that sensor node).
Now as it's my first time working with fork's, I'm not entirely sure it's working correctly.
The tcpsocket.h is a file provided, giving some basic tcp-functionality. This is working, since the data is sent and received succesfully.
Here's a short explanation of the code: The main process listens passively to incoming tcp connections. The tcp_wait_for_connection() waits in blocking mode for a connection to be established. Once this is done, it should give the connection to a new child. The Child should of course then close the passive listening on the port, and the main process should not listen to the connection with the sensor.
Now it all works fine, but I'm not sure whether children are correctly killed. A sensorNode for example just quits (cntrl + c), thus the connection stops, but I'm not sure whether the child then dies or keeps looping for eternity. I've also included tcpsocket.c since this might give more clarity.
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "tcpsocket.h"
#define BUFSIZE 1024
#define PORT 1234
struct package{
unsigned sensorId:12;
unsigned sequence:4;
unsigned flag:2;
unsigned sign:1;
unsigned value:12;
unsigned parity:1;
};
typedef struct package packs;
union sensor{
packs pack;
unsigned sensorValue;
};
typedef union sensor Sensor;
char buffer[BUFSIZE];
int main( void )
{
Socket server, client;
int bytes;
server = tcp_passive_open( PORT );
while( 1 ) {
client = tcp_wait_for_connection( server );
#ifdef DEBUG
printf("Incoming client connection\n");
#endif
pid_t pid;
pid = fork();
if(pid == -1){
printf("Something went wrong creating a child.\n");
}else if(pid == 0){
tcp_close( &server );
#ifdef DEBUG
pid_t parentPid;
parentPid = getppid();
printf("New child created with parent id %d, own pid: %d\n",parentPid, pid);
#endif
Sensor * mySensor = malloc(sizeof(packs));
while(1){
memset(buffer, 0, BUFSIZE);
bytes = tcp_receive( client, (void *)buffer, BUFSIZE );
if(bytes > 0){
mySensor->sensorValue = atoi(buffer);
#ifdef DEBUG
printf("Received message of %d bytes. ID: %i, Sequence: %i, flag: %i, sign: %i, value: %i\n",
bytes, mySensor->pack.sensorId, mySensor->pack.sequence, mySensor->pack.flag, mySensor->pack.sign, mySensor->pack.value);
#endif
}
}
tcp_close( &client );
exit(0);
}
tcp_close( &client );
}
tcp_close( &server );
return 0;
}
tcpsocket.c
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tcpsocket.h"
#define CHAR_IP_ADDR_LENGTH 16 // 4 numbers of 3 digits, 3 dots and \0
#define ERROR_SD -1
#define ERROR_PORT 0
#define MIN_PORT 1
#define MAX_PORT 65536
#define PROTOCOLFAMILY AF_INET // internet protocol suite
#define TYPE SOCK_STREAM // streaming protool type
#define PROTOCOL IPPROTO_TCP // TCP protocol
typedef struct {
int sd;
char *ip_addr;
int port;
} MySocket; // My definition of a socket: a socket descriptor,
// the IP address and port number of the PC hosting this socket
// private functions used for error checking
static void die(char* message);
static void check_socket_ptr(char *pre_msg, Socket s);
static void check_sd(char *pre_msg, int sd);
static void check_ip_addr(char *pre_msg, char *ip_addr);
static void check_port(char *pre_msg, int port);
// private error message string
static char error_msg[256];
/*-------------------------------------------------------------------------------------*/
Socket tcp_passive_open(int port)
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_port("tcp_open_server() failed", port);
MySocket *s = (MySocket *)malloc( sizeof(MySocket) );
if ( s == NULL )
die("tcp_open__socket() failed: mem alloc error");
struct sockaddr_in addr;
s->sd = socket(PROTOCOLFAMILY, TYPE, PROTOCOL);
check_sd("tcp_open_server failed(): socket creation error", s->sd);
/* Construct the server address structure */
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = PROTOCOLFAMILY;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
if ( bind(s->sd, (struct sockaddr *)&addr, sizeof(addr)) != 0 ) {
die("tcp_open_server failed(): bind() failed"); //will fail if e.g; port is in use
}
if( listen(s->sd, MAX_PENDING) != 0 )
die("tcp_open_server failed(): listen() failed");
s->port = port;
s->ip_addr = NULL; //INADDR_ANY ...
return (Socket)s;
}
/*-------------------------------------------------------------------------------------*/
Socket tcp_active_open( int remote_port, char *remote_ip )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_port("tcp_open_client() failed", remote_port);
check_ip_addr("tcp_open_client() failed", remote_ip);
MySocket *client = (MySocket *)malloc( sizeof(MySocket) );
if ( client == NULL )
die("tcp_open_client() failed: mem alloc error");
struct sockaddr_in addr;
int length;
char *p;
client->sd = socket(PROTOCOLFAMILY, TYPE, PROTOCOL);
check_sd("tcp_open_client() failed: socket creation error", client->sd);
/* Construct the server address structure */
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = PROTOCOLFAMILY;
if ( inet_aton(remote_ip, (struct in_addr *) &addr.sin_addr.s_addr) == 0 )
die("tcp_open_client failed(): invalid ip address");
addr.sin_port = htons(remote_port);
if ( connect(client->sd, (struct sockaddr *) &addr, sizeof(addr) ) < 0 )
die("tcp_open_client failed(): connect () failed");
memset(&addr, 0, sizeof(struct sockaddr_in));
length = sizeof(addr);
if ( getsockname(client->sd, (struct sockaddr *)&addr, (socklen_t *)&length) != 0 )
die("tcp_open_client failed(): getsockname() failed");
p = inet_ntoa(addr.sin_addr); //returns addr to statically allocated buffer
client->ip_addr = (char *)malloc( sizeof(char)*CHAR_IP_ADDR_LENGTH);
if ( client->ip_addr == NULL )
die("tcp_open_client failed(): mem alloc error");
client->ip_addr = strcpy( client->ip_addr, p );
client->port = ntohs(addr.sin_port);
return (Socket)client;
}
/*-------------------------------------------------------------------------------------*/
Socket tcp_wait_for_connection( Socket socket )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("tcp_wait_for_connection() failed", socket);
MySocket *serv = (MySocket *)socket;
MySocket *clie = (MySocket *)malloc( sizeof(MySocket) );
if ( clie == NULL )
die("tcp_wait_for_connection() failed: mem alloc error");
struct sockaddr_in addr;
unsigned int length = sizeof(struct sockaddr_in);
char *p;
check_sd("tcp_wait_for_connection() failed", serv->sd);
clie->sd = accept(serv->sd, (struct sockaddr*) &addr, &length);
check_sd("tcp_wait_for_connection() failed: accept() error", clie->sd);
p = inet_ntoa(addr.sin_addr); //returns addr to statically allocated buffer
clie->ip_addr = (char *)malloc( sizeof(char)*CHAR_IP_ADDR_LENGTH);
if ( clie->ip_addr == NULL )
die("tcp_wait_for_connection failed(): mem alloc error");
clie->ip_addr = strcpy( clie->ip_addr, p );
clie->port = ntohs(addr.sin_port);
return (Socket)clie;
}
/*-------------------------------------------------------------------------------------*/
void tcp_close( Socket *socket )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("tcp_close() failed", socket);
check_socket_ptr("tcp_close() failed", *socket);
MySocket *s = (MySocket *)*socket;
check_sd("tcp_close() failed", s->sd);
close( s->sd );
free(s);
*socket = NULL;
}
/*-------------------------------------------------------------------------------------*/
void tcp_send(Socket socket, void *buffer, int bufsize )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("tcp_send() failed", socket);
if ( buffer == NULL )
die("tcp_send failed(): buffer param is NULL");
MySocket *s = (MySocket *)socket;
int result;
int sen = 0;
int to_sen = bufsize;
check_sd("tcp_send() failed", s->sd);
do {
result = send(s->sd, (const void*) (buffer+sen), to_sen, 0);
if (result < 0)
die("tcp_send() failed: not able to send");
sen += result;
to_sen -= result;
} while ( to_sen > 0 );
}
/*-------------------------------------------------------------------------------------*/
int tcp_receive (Socket socket, void* buffer, int bufsize)
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("tcp_receive() failed", socket);
if ( buffer == NULL )
die("tcp_receive() failed: buffer param is NULL");
if ( bufsize == 0 )
die("tcp_receive() failed: bufsize is zero");
MySocket *s = (MySocket *)socket;
check_sd("tcp_receive() failed", s->sd);
int rec = recv(s->sd, buffer, bufsize, 0);
return rec;
}
/*-------------------------------------------------------------------------------------*/
char * get_ip_addr( Socket socket )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("get_ip_addr() failed", socket);
MySocket *s = (MySocket *)socket;
check_ip_addr("get_ip_addr() failed", s->ip_addr);
return s->ip_addr;
}
/*-------------------------------------------------------------------------------------*/
int get_port( Socket socket )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("get_port() failed", socket);
MySocket *s = (MySocket *)socket;
check_port("get_port() failed", s->port);
return s->port;
}
/*-------------------------------------------------------------------------------------*/
int get_socket_descriptor( Socket socket )
/*-------------------------------------------------------------------------------------*/
{
// parameter check
check_socket_ptr("get_socket_descriptor() failed", socket);
MySocket *s = (MySocket *)socket;
check_sd("get_socket_descriptor() failed", s->sd);
return s->sd;
}
/*-------------------------------------------------------------------------------------*/
static void die(char* message)
/*-------------------------------------------------------------------------------------*/
{
perror(message);
exit(-1);
}
/*-------------------------------------------------------------------------------------*/
static void check_socket_ptr(char *pre_msg, Socket socket)
/*-------------------------------------------------------------------------------------*/
{
if ( socket == NULL )
{
sprintf(error_msg, "%s: socket ptr is NULL", pre_msg);
die(error_msg);
}
}
/*-------------------------------------------------------------------------------------*/
static void check_sd(char *pre_msg, int sd)
/*-------------------------------------------------------------------------------------*/
{
if ( sd <= ERROR_SD )
{
sprintf(error_msg, "%s: invalid socket descriptor", pre_msg);
die(error_msg);
}
}
/*-------------------------------------------------------------------------------------*/
static void check_ip_addr(char *pre_msg, char *ip_addr)
/*-------------------------------------------------------------------------------------*/
{
if ( ip_addr == NULL )
{
sprintf(error_msg, "%s: invalid socket ip address", pre_msg);
die(error_msg);
}
}
/*-------------------------------------------------------------------------------------*/
static void check_port(char *pre_msg, int port)
/*-------------------------------------------------------------------------------------*/
{
if ( (port < MIN_PORT) || (port > MAX_PORT) )
{
sprintf(error_msg, "%s: invalid socket port", pre_msg);
die(error_msg);
}
}
I'm not sure whether the child then dies or keeps looping for eternity.
In the code you show there are no tests for recv() returning 0 which would indicate that the connection had been closed by the other side.
You might like to modify the code like this
if(bytes > 0){
mySensor->sensorValue = atoi(buffer);
#ifdef DEBUG
printf("Received message of %d bytes. ID: %i, Sequence: %i, flag: %i, sign: %i, value: %i\n",
bytes, mySensor->pack.sensorId, mySensor->pack.sequence, mySensor->pack.flag, mySensor->pack.sign, mySensor->pack.value);
#endif
}
else if (bytes == 0)
{
printf("Connection closed by other side. Exiting ...\n");
break;
}
else /* bytes < 0 */
{
printf("Error receiving. Exiting ...\n");
break;
}
to end the child. There is no need to "kill" any process in term of sending it a SIGKILL signal, btw.
Also the tcp_receive() function misses to test how much data had been received for each call to recv() and then if necessary to loop around recv() until all data requested had been received. (See tcp_send() to see how it is done for send().)
I have two machines, that I would like both of them to communicate using sockets under C programming language.
I have developed two samples to represent both sides but I noticed that I can send data successfully if they are smaller than certain number.
The size that I have tested but does not work is sending & receiving 2048 bytes , on contrary, for other smaller sizes such as 258 Bytes, 1KByte it works fine.
After doing some investigations, I found out that, the sending operation has no errors while for the reception, I did not get any thing at all.
I have checked the sending and receiving buffer sizes on both machines and I guess they are sufficient.
Here are the first side of my code:
/* UDP client in the internet domain */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#define BUFF_SIZE 1800
#define MOBIPASS_L2_IP_ADDRESS "192.168.13.53"
#define MOBIPASS_L2_PORT_NUM 12001
#define BRIDGE_IP_ADDRESS "192.168.13.30"
#define BRIDGE_PORT_NUM 12000
#define RESTRICT_SRC_DST_NUM 1
#define TEN_MSEC 10000
void error(const char *);
void adjustSockParam (int sockFD);
int main(int argc, char *argv[])
{
#if RESTRICT_SRC_DST_NUM
int bridge_sock_fd = -1, n =-1;
struct sockaddr_in server_mobipass, client_bridge;
char buffer[BUFF_SIZE];
char* choice = NULL;
size_t size = 1;
/* create socket descriptor at client machine*/
bridge_sock_fd= socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (bridge_sock_fd < 0) error("socket");
/* *********************************************************
* prepare source information of the socket file descriptor
* *********************************************************
*/
client_bridge.sin_family = AF_INET;
client_bridge.sin_addr.s_addr=inet_addr(BRIDGE_IP_ADDRESS) ;
client_bridge.sin_port = htons(BRIDGE_PORT_NUM);
if( bind( bridge_sock_fd, (struct sockaddr *) &client_bridge, sizeof ( client_bridge ) ) < 0 )
{
error( "bind" );
}
/* *********************************************************
* prepare destination information of the socket file descriptor
* *********************************************************
*/
server_mobipass.sin_family = AF_INET;
server_mobipass.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS) ;
server_mobipass.sin_port = htons(MOBIPASS_L2_PORT_NUM);
if( connect( bridge_sock_fd, (struct sockaddr *) &server_mobipass, sizeof ( server_mobipass ) ) < 0 ) {
error("connect");
}
adjustSockParam(bridge_sock_fd);
do
{
printf("sending traffic?[y/n]\n");
getline(&choice,&size,stdin);
if(*choice=='n')
break;
strncpy( buffer,
"Hello Mobipass, this is bridge :)\n",
sizeof(buffer));
n = send( bridge_sock_fd, buffer, sizeof(buffer), MSG_CONFIRM );
if( n < 0 )
{
error( "send" );
}
assert(n == sizeof(buffer));
usleep(TEN_MSEC);
/*memset(buffer,0 , sizeof(buffer));
if( recv( bridge_sock_fd, buffer, sizeof(buffer), 0 ) < 0 )
{
error( "recv" );
}
else
{
printf("Msg received from mobipass is:\n%s",buffer);
}*/
}while(*choice == 'y' || *choice == 'Y');
close( bridge_sock_fd );
#else
int tx_sock, n, rx_sock;
unsigned int srv_length;
struct sockaddr_in server_mobipass, from, server_bridge;
char buffer[256];
/* create socket descriptor at client machine*/
tx_sock= socket(AF_INET, SOCK_DGRAM, 0);
if (tx_sock < 0) error("socket");
srv_length=sizeof(struct sockaddr_in);
/*prepare server (peer entity) of UDP connection*/
server_mobipass.sin_family = AF_INET;
server_mobipass.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS) ;
server_mobipass.sin_port = htons(MOBIPASS_L2_PORT_NUM);
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n=sendto(tx_sock,buffer,
strlen(buffer),0,(const struct sockaddr *)&server_mobipass,srv_length);
if (n < 0) error("Sendto");
rx_sock= socket(AF_INET, SOCK_DGRAM, 0);
if (rx_sock < 0) error("socket");
server_bridge.sin_family = AF_INET;
server_bridge.sin_addr.s_addr = inet_addr(BRIDGE_IP_ADDRESS);
server_bridge.sin_port = htons(BRIDGE_PORT_NUM);
if (bind(rx_sock,(struct sockaddr *)&server_bridge,srv_length)<0)
error("binding");
n = recvfrom(rx_sock,buffer,256,0,(struct sockaddr *)&from, &srv_length);
if (n < 0) error("recvfrom");
/*print to stdout what have been received*/
write(1,"Got an ack: ",12);
write(1,buffer,n);
/* close sockets */
close(rx_sock);
close(tx_sock);
#endif /* RESTRICT_SRC_DST_NUM */
return 0;
}
void error(const char *msg)
{
perror(msg);
exit(0);
}
void adjustSockParam (int sockFD)
{
int option_value;
socklen_t option_len = sizeof(option_value);
/** Adjust Send Buffer Size**/
if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
&option_value, &option_len)< 0)
{
error("get Socket Option error:");
}
printf("Initial SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);
/*option_value = 2048;
if( setsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
&option_value, option_len)< 0)
{
error("get Socket Option error:");
}
if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
&option_value, &option_len)< 0)
{
error("get Socket Option error:");
}
printf("Final SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);*/
/** Adjust Receiver Buffer Size **/
if( getsockopt(sockFD, SOL_SOCKET, SO_RCVBUF,
&option_value, &option_len)< 0)
{
error("get Socket Option error:");
}
printf("Initial SO_RCVBUF: option_len = %d option_value = %d\n",option_len,option_value);
}
Here are the second side of my code:
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <assert.h>
#define BUFF_SIZE 1800
#define MOBIPASS_L2_IP_ADDRESS "192.168.13.53"
#define MOBIPASS_L2_PORT_NUM 12001
#define BRIDGE_IP_ADDRESS "192.168.13.30"
#define BRIDGE_PORT_NUM 12000
#define DUMP 0
#define ACT_AS_STRING 0
#define RESTRICT_SRC_DST_NUM 1
#define TEN_MSEC 10000
#if DUMP
#define DUMP_BUFFER(buf,len) \
{ \
int i; \
for(i = 0; i < len; i++) \
printf("buf[%d] = 0x%x",i,buf[i]); \
}
#else
#define DUMP_BUFFER(buf,len) printf("received len=%d\n",len)
#endif
void adjustSockParam (int sockFD);
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
#if RESTRICT_SRC_DST_NUM
int mobipass_sock_fd = -1;
struct sockaddr_in server_mobipass, client_bridge;
char buffer[BUFF_SIZE];
int recivedBytes=-1;
printf("size of buffer = %d\n",sizeof(buffer));
/* create socket descriptor at client machine*/
mobipass_sock_fd= socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (mobipass_sock_fd < 0) error("socket");
/* *********************************************************
* prepare source information of the socket file descriptor
* *********************************************************
*/
client_bridge.sin_family = AF_INET;
client_bridge.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS) ;
client_bridge.sin_port = htons(MOBIPASS_L2_PORT_NUM);
if( bind( mobipass_sock_fd, (struct sockaddr *) &client_bridge, sizeof ( client_bridge ) ) < 0 )
{
error( "bind" );
}
/* *********************************************************
* prepare destination information of the socket file descriptor
* *********************************************************
*/
server_mobipass.sin_family = AF_INET;
server_mobipass.sin_addr.s_addr=inet_addr(BRIDGE_IP_ADDRESS) ;
server_mobipass.sin_port = htons(BRIDGE_PORT_NUM);
if( connect( mobipass_sock_fd, (struct sockaddr *) &server_mobipass, sizeof ( server_mobipass ) ) < 0 ) {
error("connect");
}
adjustSockParam(mobipass_sock_fd);
printf("waiting for message from bridge:\n");
do{
memset(buffer,0 , sizeof(buffer));
recivedBytes = recv( mobipass_sock_fd, buffer, sizeof(buffer), 0 );
if( recivedBytes < 0 )
{
error( "recv" );
}
else
{
assert(recivedBytes == sizeof(buffer));
DUMP_BUFFER(buffer,recivedBytes);
#if ACT_AS_STRING
printf("Msg received from bridge is:\n%s",buffer);
#endif
}
usleep(TEN_MSEC);
#if ACT_AS_STRING
strncpy( buffer,
"Hello Bridge, this is mobipass :)\n",
sizeof(buffer));
if( send( mobipass_sock_fd, buffer, sizeof(buffer), 0 ) < 0 )
{
error( "send" );
}
#endif
}while(1);
close( mobipass_sock_fd );
#else
int tx_sock, n, rx_sock;
unsigned int srv_length;
socklen_t fromlen;
struct sockaddr_in server_mobipass, from, server_bridge;
char buf[1024];
rx_sock=socket(AF_INET, SOCK_DGRAM, 0);
if (rx_sock < 0) error("Opening socket");
else printf("Creating rx udp socket\n");
srv_length = sizeof(server_mobipass);
bzero(&server_mobipass,srv_length);
server_mobipass.sin_family=AF_INET;
server_mobipass.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS);
server_mobipass.sin_port=htons(MOBIPASS_L2_PORT_NUM);
if (bind(rx_sock,(struct sockaddr *)&server_mobipass,srv_length)<0)
error("binding");
else
printf("Binding a socket to a server IP address\n");
fromlen = sizeof(struct sockaddr_in);
tx_sock=socket(AF_INET, SOCK_DGRAM, 0);
if (tx_sock < 0) error("Opening socket");
else printf("Creating tx udp socket\n");
server_bridge.sin_family=AF_INET;
server_bridge.sin_addr.s_addr=inet_addr(BRIDGE_IP_ADDRESS);
server_bridge.sin_port=htons(BRIDGE_PORT_NUM);
while (1)
{
printf("waiting for a message from client side:\n");
n = recvfrom(rx_sock,buf,1024,0,(struct sockaddr *)&from,&fromlen);
if (n < 0) error("recvfrom");
write(1,"Message received from eNB machince:\n",36);
write(1,buf,n);
n = sendto(tx_sock,"hello eNB, I am mobipass\n",27,
0,(struct sockaddr *)&server_bridge,fromlen);
if (n < 0) error("sendto");
}
#endif
return 0;
}
void adjustSockParam (int sockFD)
{
int option_value;
socklen_t option_len = sizeof(option_value);
/** Adjust Send Buffer Size**/
if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
&option_value, &option_len)< 0)
{
error("get Socket Option error:");
}
printf("Initial SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);
/* option_value = 2048;
if( setsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
&option_value, option_len)< 0)
{
error("get Socket Option error:");
}
if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
&option_value, &option_len)< 0)
{
error("get Socket Option error:");
}
printf("Final SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);*/
/** Adjust Receiver Buffer Size **/
if( getsockopt(sockFD, SOL_SOCKET, SO_RCVBUF,
&option_value, &option_len)< 0)
{
error("get Socket Option error:");
}
printf("Initial SO_RCVBUF: option_len = %d option_value = %d\n",option_len,option_value);
}
Here is the output on first side:
Initial SO_SNDBUF: option_len = 4 option_value = 112640
Initial SO_RCVBUF: option_len = 4 option_value = 112640
sending traffic?[y/n]
y
sending traffic?[y/n]
y
Here is the output on second side:
size of buffer = 1800
Initial SO_SNDBUF: option_len = 4 option_value = 1048576
Initial SO_RCVBUF: option_len = 4 option_value = 1048576
waiting for message from bridge:
I am not sure what I am doing wrong here. Do you any suggestions?
While UDP datagram packet size could be up to 64K (16-bit data length field), the usual underlying data link technology - ethernet - has a frame size of 1500 bytes. Less at least 20 bytes for IP header, less 8 bytes of UDP header, that leaves only 1472 bytes for UDP payload that could be sent without IP fragmentation, which usually leads to issues like in your case where packets are just dropped somewhere.
Most UDP-based protocols restrict datagram size for exactly this reason.
I have a program that is supposed to both read a serial port and from tcp/ip socket simultaneously.
However, I only can see the serial information when I receive a message via socket. I believe that it has something to do with blocking/nonblocking of the accept() method. However, I have been unsuccessful in figuring out how to add flags to it.
Anyone have any ideas?
Do I have to rewrite the whole thing or can I just add a flag?
int main(int argc, char *argv[]) {
int list_s; /* listening socket */
int conn_s; /* connection socket */
short int port; /* port number */
struct sockaddr_in servaddr; /* socket address structure */
char buffer[MAX_LINE]; /* character buffer */
char *endptr; /* for strtol() */
/* Get port number from the command line, and
* set to default port if no arguments were supplied */
if ( argc == 2 ) {
port = strtol(argv[1], &endptr, 0);
if ( *endptr ) {
fprintf(stderr, "ECHOSERV: Invalid port number.\n");
exit(EXIT_FAILURE);
}
}
else if ( argc < 2 ) {
port = ECHO_PORT;
}
else {
fprintf(stderr, "ECHOSERV: Invalid arguments.\n");
exit(EXIT_FAILURE);
}
/* Create the listening socket */
if ( (list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
fprintf(stderr, "ECHOSERV: Error creating listening socket.\n");
exit(EXIT_FAILURE);
}
/* Set all bytes in socket address structure to
* zero, and fill in the relevant data members */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
/* Bind our socket addresss to the
* listening socket, and call listen() */
if ( bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling bind()\n");
exit(EXIT_FAILURE);
}
if ( listen(list_s, LISTENQ) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling listen()\n");
exit(EXIT_FAILURE);
}
/* Enter an infinite loop to respond
* to client requests and echo input */
int result = 0;
int portID = -1;
char *device = "/dev/ttyUSB1";
int rate = convertRate("115200");
char parity = convertParity("N");
int databits = convertDatabits("8");
int stopbits = convertStopbits("1");
portID = posixComOpen(device,rate,parity,databits,stopbits);
while ( 1 ) {
char input = 0;
while(posixComDataReady(portID) && posixComRead(portID, &input)) {
printf("%c", input);
} //while
/* Write character to Vex */
if(posixComWrite(portID, 'x') < 0)
printf("POSIX: Error Writing char %c",'x');
/* Wait for a connection, then accept() it */
if ( (conn_s = accept(list_s, NULL, NULL) ) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling accept()\n");
exit(EXIT_FAILURE);
}
/* Retrieve an input line from the connected socket
* then simply write it back to the same socket. */
Readline(conn_s, buffer, MAX_LINE-1);
printf("Netbook got a TCP/IP message: %s\n", buffer);
char* sendMessage = "Thanks for the message!";
Writeline(conn_s,sendMessage , strlen(sendMessage));
/* Close the connected socket */
if ( close(conn_s) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling close()\n");
exit(EXIT_FAILURE);
}
}//while
return 0;
}
You're right, the problem is that accept blocks until there is a new connection.
I don't know how serial connections work, but you might want to look at the select function, which allows you to wait on several different file descriptors, and respond to them when there is data on the other end.
Here's an example of how to use select for sockets: Server Example