I googled a lot and didn't get an answer, hence posting it here.
In the following C program(the server code) I want a Unix domain socket server that's listening at /tmp/unix-test-socket. My problem is that the client code is sucessfully able to connect to the server. However, once its connected and I have "accepted" the connection, the select call does NOT block.
So let me explain.
Initially the unix_domain_socket = 3
As soon as I get the first request, accept the connection and, store it in unix_domain_socket_connections[max_unix_domain_socket_connections]. The value of the socket fd is 4.
When I run the server code goes into a loop because the select call believes that always there is data in socket 4.
I run the CLIENT side as:
./unix-client "/tmp/unix-test-socket" SEND_DATA
Output from the SERVER side:
Client sent us a message!
Successfully accepted the new ION connection with fd 4!
[program_select_to_look_at_right_sockets]: Storing fd 4
Data Arrived on UNIX domain socket 4
length 10 SEND_DATA <-- I get the data sent by the client
[program_select_to_look_at_right_sockets]: Storing fd 4 *<-- Why isnt select blocking and why does it think there is still data on socket 4*
Data Arrived on UNIX domain socket 4
[program_select_to_look_at_right_sockets]: Storing fd 4
Data Arrived on UNIX domain socket 4
SERVER CODE:
int unix_domain_socket = 0;
int max_unix_domain_socket_connections;
int unix_domain_socket_connections[2];
char *unix_domain_socket_name = "/tmp/unix-test-socket";
int open_unix_domain_server()
{
int socket_fd, result;
struct sockaddr_un name;
int client_sent_quit_message;
socklen_t socket_length;
max_unix_domain_socket_connections = 0;
memset((void *) &name, 0, sizeof(name));
socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
name.sun_family = AF_UNIX;
strcpy(name.sun_path, unix_domain_socket_name);
socket_length = strlen(name.sun_path) + sizeof(name.sun_family);
/* Remove this socket if it already exists */
unlink(name.sun_path);
result = bind(socket_fd, (struct sockaddr *) &name, socket_length);
if (result < 0)
goto Error;
result = listen(socket_fd, MAX_UNIX_DOMAIN_SOCKETS);
return socket_fd;
Error:
printf("[%s] Error in either listen or bind!\n", __FUNCTION__);
return -1;
}
int accept_new_unix_domain_connection()
{
int client_fd;
struct sockaddr_un new_connection;
socklen_t new_conn_length = sizeof(new_connection);
memset((void *) &new_connection, 0, sizeof(new_connection));
client_fd = accept(unix_domain_socket, (struct sockaddr *) &new_connection,
&new_conn_length);
if (client_fd < 0)
{
printf("The following error occurred accept failed %d %d\n", errno,
unix_domain_socket);
}
unix_domain_socket_connections[max_unix_domain_socket_connections] =
client_fd;
max_unix_domain_socket_connections++;
return client_fd;
}
int check_if_new_client_is_unix_domain(fd_set readfds)
{
int unix_fd = 0;
for (unix_fd = 0; unix_fd < 2; unix_fd++)
{
if (FD_ISSET(unix_domain_socket_connections[unix_fd], &readfds))
{
printf("Data Arrived on UNIX domain socket %d\n",
unix_domain_socket_connections[unix_fd]);
return 1;
}
}
return 0;
}
int process_data_on_unix_domain_socket(int unix_socket)
{
int length = 0;
char* data_from_gridFtp;
/* First, read the length of the text message from the socket. If
read returns zero, the client closed the connection. */
if (read(unix_socket, &length, sizeof(length)) == 0)
return 0;
/* Allocate a buffer to hold the text. */
data_from_gridFtp = (char*) malloc(length + 1);
/* Read the text itself, and print it. */
recv(unix_socket, data_from_gridFtp, length, 0);
printf("length %d %s\n", length, data_from_gridFtp);
return length;
}
void program_select_to_look_at_right_sockets(fd_set *readfds, int *maxfds)
{
int unix_fd = 0;
FD_ZERO(readfds);
FD_SET(unix_domain_socket, readfds);
for (unix_fd = 0; unix_fd < 2; unix_fd++)
{
if (unix_domain_socket_connections[unix_fd])
{
printf("[%s]: Storing fd %d\n", __FUNCTION__,
unix_domain_socket_connections[unix_fd]);
FD_SET(unix_domain_socket_connections[unix_fd], readfds);
if (*maxfds < unix_domain_socket_connections[unix_fd])
*maxfds = unix_domain_socket_connections[unix_fd];
}
}
}
int main(int argc, char**argv)
{
int result, maxfds, clientfd, loop;
fd_set readfds;
int activity;
socklen_t client_len;
struct sockaddr_in client_address;
FD_ZERO(&readfds);
unix_domain_socket = open_unix_domain_server();
if (unix_domain_socket < 0)
return -1;
maxfds = unix_domain_socket;
FD_SET(unix_domain_socket, &readfds);
for (loop = 0; loop < 4; loop++)
{
program_select_to_look_at_right_sockets(&readfds, &maxfds);
activity = select(maxfds + 1, &readfds, NULL, NULL, NULL);
if (FD_ISSET(unix_domain_socket, &readfds))
{
printf("client sent us a message!\n");
clientfd = accept_new_unix_domain_connection();
if (clientfd < 0)
break;
}
else if (check_if_new_client_is_unix_domain(readfds))
{
process_data_on_unix_domain_socket(clientfd);
}
}
}
CLIENT CODE:
/* Write TEXT to the socket given by file descriptor SOCKET_FD. */
void write_text(int socket_fd, const char* text)
{
/* Write the number of bytes in the string, including
NUL-termination. */
int length = strlen(text) + 1;
send(socket_fd, &length, sizeof(length), 0);
/* Write the string. */
send(socket_fd, text, length, 0);
}
int main(int argc, char* const argv[])
{
const char* const socket_name = argv[1];
const char* const message = argv[2];
int socket_fd;
struct sockaddr_un name;
/* Create the socket. */
socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
/* Store the server’s name in the socket address. */
name.sun_family = AF_UNIX;
strcpy(name.sun_path, socket_name);
/* Connect the socket. */
connect(socket_fd, (struct sockaddr *) &name, SUN_LEN(&name));
/* Write the text on the command line to the socket. */
write_text(socket_fd, message);
close(socket_fd);
return 0;
}
You will find that select() will return "ready for reading" if the far end has closed... The rule for "ready for reading" is that it is true iff a read() would not block. read() does not block if it returns 0.
According to the select linux man pages there is a bug related to this behaviour:
Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready.
On the other hand, I recommend you to consider the strategy for handle activity and process data into the loop(irrelevant parts removed):
for (loop = 0; loop<4; loop++)
{
// ...
activity = select( maxfds + 1 , &readfds , NULL , NULL , NULL);
// ...
}
This will block for the first sockect while the 2nd, 3th, and fourth might be ready. At least use a timeout and check errno for handle timeout event. See select man pages for more info.
Related
EDIT1: Per request of John Bollinger, I've included the full client and server code below.
I am sending 4-digit penny prices over a socket connection; e.g., 43.75, 29.43, 94.75, etc. Buffer size is set to 1024 bytes. At the moment, I am converting float prices to c-strings for transmission--not optimal, but I'm working on it. By my calculations, price size is 6 bytes: 4 digits, a decimal point, and the c-string terminating character '\0'.
The problem is that, on the client side, prices are not printed until the 1024-byte buffer is full. I would like each price tick sent and handled as it comes in, and force a buffer flush, and have each tick to be handled separately. In other words, I'd like each price to be sent in a separate packet, and not buffer the 1024 bytes.
How can I force each price tick to be handled separately? Thanks for your help. Sincerely, Keith :^)
The socket connection code is taken from the following url:
http://www.programminglogic.com/example-of-client-server-program-in-c-using-sockets-and-tcp/
Server-side:
char buffer[1024]; // buffer set to 1024
char res[1024] // res contains the a float rounded and converted to a string.
// res is copied into buffer, and then sent with size 6:
// 22.49\0 = 6 characters.
strcpy(buffer, res);
send(newSocket,buffer,6,0);
Client-side:
while(1) {
recv(clientSocket, buffer, 1024, 0);
printf("%s ",buffer);
}
I would expect the prices to print as they arrive, like so:
pickledEgg$ 49.61
pickledEgg$ 50.20
pickledEgg$ 49.97
pickledEgg$ etc..
but 1024 bytes worth of prices are being buffered:
pickledEgg$ 49.61 50.20 49.97 49.86 49.52 50.24 49.79 49.52 49.84 50.29 49.83 49.97 50.34 49.81 49.84 49.50 50.08 50.06 49.54 50.04 50.09 50.08 49.54 50.43 49.97 50.33 50.29 50.08 50.43 50.02 49.86 50.06 50.24 50.33 50.43 50.25 49.58 50.25 49.79 50.43 50.04 49.63 49.88 49.86 49.93 50.22 50.38 50.02 49.79 50.41 49.56 49.88 49.52 49.59 50.34 49.97 49.93 49.63 50.06 50.38 50.15 50.43 49.95 50.40 49.77 50.40 49.68 50.36 50.13 49.95 50.29 50.18 50.09 49.66 50.06 50.04 50.38 49.95 49.56 50.18 49.86 50.13 50.09 49.88 49.74 49.91 49.88 49.70 49.56 50.43 49.58 49.74 49.88 49.54 49.63 50.15 49.97 49.79 49.52 49.59 49.77 50.31 49.81 49.88 50.47 50.36 50.40 49.86 49.81 49.97 49.54 50.18 50.11 50.13 50.08 50.36 50.06 50.45 50.06 50.13 50.38 49.65 49.88 50.29 49.70 50.00 50.45 49.68 50.29 50.47 50.29 50.09 50.27 49.59 50.45 50.24 50.47 49.88 50.11 49.77 49.86 50.16 49.97 50.47 50.31 49.56 49.84 50.38 50.02 50.40 49.52 49.90 50.09 49.90 50.20 49.81 50.38 50.15 49.99 49.70 50.11 49.77 49.79 49.88 49.88 49.75 50.13 50.36 49.63 49.74 50.1
EDIT1: Server-side code:
/****************** SERVER CODE ****************/
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
void reverse(char *str, int len)
{
int i=0, j=len-1, temp;
while (i<j)
{
temp = str[i];
str[i] = str[j];
str[j] = temp;
i++; j--;
}
}
int intToStr(int x, char str[], int d)
{
int i = 0;
while (x)
{
str[i++] = (x%10) + '0';
x = x/10;
}
// If number of digits required is more, then
// add 0s at the beginning
while (i < d)
str[i++] = '0';
reverse(str, i);
str[i] = '\0';
return i;
}
void ftoa(float n, char *res, int afterpoint)
{
// Extract integer part
int ipart = (int)n;
// Extract floating part
float fpart = n - (float)ipart;
// convert integer part to string
int i = intToStr(ipart, res, 0);
// check for display option after point
if (afterpoint != 0)
{
res[i] = '.'; // add dot
// Get the value of fraction part upto given no.
// of points after dot. The third parameter is needed
// to handle cases like 233.007
// fpart = fpart * pow(10, afterpoint);
fpart = fpart * 100;
intToStr((int)fpart, res + i + 1, afterpoint);
}
}
float randPrice() {
int b;
float d;
b = 4950 + rand() % 100 + 1;
d = (float)b/100;
return d;
}
void wait() {
int i, j, k;
for (i=0; i<10000; ++i) {
for (j=0; j<10000; ++j) {
k = i + j + i * j;
}
}
}
int main(){
int welcomeSocket, newSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
char res[1024];
float n;
srand(time(NULL));
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
welcomeSocket = socket(PF_INET, SOCK_STREAM, 0);
/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(7891);
/* Set IP address to localhost */
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Bind the address struct to the socket ----*/
bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
/*---- Listen on the socket, with 5 max connection requests queued ----*/
if(listen(welcomeSocket,5)==0)
printf("Listening\n");
else
printf("Error\n");
/*---- Accept call creates a new socket for the incoming connection ----*/
addr_size = sizeof serverStorage;
newSocket = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
/*---- Send prices to the socket of the incoming connection ----*/
while(1) {
n = randPrice(); // Get a random, float price
ftoa(n, res, 2); // Convert price to string
strcpy(buffer, res); // copy to buffer
send(newSocket,buffer,6,0); // send buffer
wait();
}
return 0;
}
Client-side code:
/****************** CLIENT CODE ****************/
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
void wait() {
int i, j, k;
for (i=0; i<10000; ++i) {
for (j=0; j<10000; ++j) {
k = i + j + i * j;
}
}
}
int main(){
int clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
socklen_t addr_size;
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(7891);
/* Set IP address to localhost */
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Connect the socket to the server using the address struct ----*/
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
/*---- Read the message from the server into the buffer ----*/
int r = 0;
while(1) {
r = recv(clientSocket, buffer, 1024, 0);
printf("recv value: %i\n", r);
printf("%s ",buffer);
wait();
}
return 0;
}
It is recv() that is buffering 1024 bytes.
You have 2 options:
Read character-by-character (buffer size = 1). Inefficient but simple.
Set O_NONBLOCK using fcntl() on client side and use select() to wait till there is data to read and then call recv(). Complex, you could get any number of data or even partial data, but it is going to be efficient.
My apologies for lack of clarity in my comment.
It is impossible to reliably separate data based solely on the packet in which it arrived. Disabling Nagle's Algorithm with TCP_NODELAY may greatly improve the likelihood of getting the desired behaviour but nothing can guarantee it.
For example:
Message A is written and sent immediately
Message B is written and sent immediately
Message A is delayed on the network (too many possible reasons to list)
Message B arrives at receiver
Message A arrives at receiver
Receiver makes Messages A and B available
recv will read everything from the buffer, Message A and Message B, up to the maximum number of bytes requested. Without some method of telling Message A from Message B, you cannot proceed.
OK, but you know the length of Message A and Message B, 6 bytes, so you simply recv 6 bytes. Right?
Almost. For a number of reasons, the sender may not be able to send the whole message in one packet and a recv for 6 bytes only returns, say, 2.
The only way to be sure, other than nuking the site from orbit, is to loop on recv until all 6 bytes have been read.
bool receiveAll(int sock,
char * bufp,
size_t len)
{
int result;
size_t offset = 0;
while (len > 0)
{ // loop until we have all of our data
result = recv(sock, &bufp[offset], len, 0);
if (result < 0)
{ // Socket is in a bad state
// handle error
return false;
}
else if (result == 0)
{ // socket closed
return false;
}
len -= result;
offset += result;
}
return true;
}
Usage:
while(receiveAll(clientSocket, buffer 6)) {
printf("%s ",buffer);
}
This will keep looping until the socket is closed or an error forces the loop to exit. No waiting is required, recv waits for you.
What it doesn't have is a good mechanism for a polite shutdown of the client while the server is still running.
This allows the sender to remain stupid. Otherwise the sender needs to do something similar making sure that it only ever sends full messages, and no messages ever straddle multiple packets. This is significantly more effort to get right than the loop in the receiveAll function. See Akash Rawal's answer for hints on how to do this.
readme.txt file:
To use the program you should compile the file "main.cpp" and subsequently run the executable passing as the first argument the port number to
which the application will listen for incoming data points (the incomplete data set that is used to approximate the original signal), (argv[1]=port number).
Incoming packets should adhere to the following format:
0|numSensors(int32_t)|numMeasures(int32_t)|ToM(int32_t)|
3|sensorId(int16_t)|value(float)|timestamp(int64_t)|
3|sensorId(int16_t)|value(float)|timestamp(int64_t)|
3|sensorId(int16_t)|value(float)|timestamp(int64_t)|
3|sensorId(int16_t)|value(float)|timestamp(int64_t)|
....
2|
"numMeasures" is the number of measures for taken for each sensor (you must provide at least 3 measures per
sensor as otherwise you cannot build the training set).
"ToM" indicates the type of measurement, specifically:
0 for TEMPERATURE
1 for HUMIDITY
2 for LUMINOSITY1
"sensorID": is the unique ID for the sensor that is sending the data
"value": is the sensor reading
"timestamp": you guess ...
This is the format of the packets returned by the signal reconstruction algorithm:
4|next_p_tx(float)|
3|sensorId(int16_t)|value(float)|timestamp(int64_t)|
3|sensorId(int16_t)|value(float)|timestamp(int64_t)|
3|sensorId(int16_t)|value(float)|timestamp(int64_t)|
3|sensorId(int16_t)|value(float)|timestamp(int64_t)|
....
2|
"next_p_tx": is the transmission probability for the sensors, for the next data gathering round, see our publications for further info on the approach.
my question:
how to run this program on Ubuntu ? (via commandline or any IDE)
int main(int argc, char *argv[]) {
initMeasures = (sensorMeasures*) malloc(sizeof(sensorMeasures));
fprintf(stdout, "Starting...\n");
int serversock, clientsock;
struct sockaddr_in server, client;
if (argc != 2) {
fprintf(stderr, "USAGE: echoserver <port>\n");
exit(1);
}
/* Create the TCP socket */
if ((serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
Die("Failed to create socket");
}
/* Construct the server sockaddr_in structure */
memset(&server, 0, sizeof(server)); /* Clear struct */
server.sin_family = AF_INET; /* Internet/IP */
server.sin_addr.s_addr = htonl(INADDR_ANY); /* Incoming addr */
server.sin_port = htons(atoi(argv[1])); /* server port */
/* Bind the server socket */
if (bind(serversock, (struct sockaddr *) &server, sizeof(server)) < 0) {
Die("Failed to bind the server socket");
} else {
fprintf(stdout, "Bind successful...\n");
}
/* Listen on the server socket */
if (listen(serversock, MAXPENDING) < 0) {
Die("Failed to listen on server socket");
} else {
fprintf(stdout, "Listen successful...\n");
}
/*
* Initialization of "last"
*/
for (int i = 0; i < 5; i++) {
last[i].Phi_prec = new Matrix(1, 1);
(*last[i].Phi_prec)(1, 1) = 0;
last[i].x_prec = new ColumnVector(1);
(*last[i].x_prec)(1) = 0;
last[i].y_prec = new ColumnVector(1);
(*last[i].y_prec)(1) = 0;
last[i].p_tx = 1.0;
last[i].depth = 0;
}
/* Run until cancelled */
while (1) {
unsigned int clientlen = sizeof(client);
printf("Wait for client connection...\n");
if ((clientsock = accept(serversock, (struct sockaddr *) &client,
&clientlen)) < 0) {
Die("Failed to accept client connection");
}
fprintf(stdout, "Client connected: %s:%d\n",
inet_ntoa(client.sin_addr), ntohs(client.sin_port));
now = time(NULL);
receiveData(clientsock); // receive socket data
reconstruct(); // reconstruct received data
sendResults(clientsock); // return reconstructed data to web application
printf("All operations successfully completed...\n");
}
free(initMeasures);
exit(EXIT_SUCCESS);
}
To use the program you should compile the file "main.cpp"
That's g++ -Wall -Wextra -o echoserver main.cpp
and subsequently run the executable passing as the first argument the port number
That's ./echoserver 12345 replacing the number with whichever port you want to listen to.
I will attempt to be concise while providing the necessary information in order to get the help, from the talented folks here.
The scenario:
Two programs communicate, one (program 2) sends multicast information to the other (program 1), who needs to receive and do some computation and send them back to program 2. Program 2 is multicast capable like mentioned, but also receives unicast, which is the way it receives the data from Program 1.
Program 1: receives in multicast and responds in unicast to program 2
Program 2: sends in multicast and receives in unicast from program 1.
The OS:
Linux Centos
The ISSUE:
The same programs, when i take program 1 to another computer while leaving program 2 in the other and let them communicate over different IP addresses. All is nice and dandy.
But when i run them on the same computer using the same IP address but different Port, they communicate in one socket, but program 2 doesn't see the computed data coming from program 1. Program 1 does calculate and send (sendto return is positive).
I used tcpdump, and effectively nothing coming on the port of program 1, but i can see program 1 having sent the periodic data in socket 1 of program 1.
Now, the fun and concise part:
The code of PROGRAM 1 (PROGRAM 2 is unavailable for disclosure, it is make installed):
struct ConfigStruct
{
struct sockaddr_in Hinfo1, Hinfo2;
struct sockaddr_in Rinfo;
int sock1, sock2;
};
int main()
{
ConfigStruct StructArg;
int fd1, fd2;
int POS(1);
/****************** Network parameters declaration *************************/
// Declaration for socket addresses
struct sockaddr_in Host_info1, Host_info2;
struct sockaddr_in Remote_info;
struct in_addr localInterface;
struct ip_mreq Group;
memset((char *)&Host_info1,0,sizeof(Host_info1));
memset((char *)&Host_info2,0,sizeof(Host_info2));
memset((char *)&Remote_info,0,sizeof(Remote_info));
memset((char *)&Group,0,sizeof(Group));
//**** Reads configuration file****************
cout<<"Reading configuration file..........."<<endl;
std::string input1 ="192.***.**.**";
std::string input2 = "8888";
std::string input3 ="192.***.**.**";
std::string input4 = "8889";
const char* addr_input = input1.data();
const char* port_input = input2.data();
const char* addr_input2 = input3.data();
const char* port_input2 = input4.data();
Remote_info.sin_addr.s_addr=inet_addr(addr_input);
Remote_info.sin_port = htons((uint16_t)stoi(port_input,nullptr,0));
Remote_info.sin_family=AF_INET;
Host_info1.sin_addr.s_addr=inet_addr(addr_input2);//htonl(INADDR_ANY);
Host_info1.sin_port = htons((uint16_t)stoi(port_input2,nullptr,0));
Host_info1.sin_family=AF_INET;
//***** First socket *******
fd1= socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if (fd1 == -1)
{
std::cout<<"A problem occured"<<endl;
cease("socket", wd) ;
}
if (setsockopt(fd1,SOL_SOCKET,SO_REUSEADDR, &POS, sizeof(POS)) == -1)
{
perror(" Error in setsockopt");
exit(1);
}
// **** I'M NOT SURE IF THIS NECESSARY **************
int opts;
opts = fcntl(fd1,F_GETFL);
if (opts < 0)
{
perror("fcntl(F_GETFL)");
exit(EXIT_FAILURE);
}
opts = (opts | O_NONBLOCK);
if (fcntl(fd1,F_SETFL,opts) < 0)
{
perror("fcntl(F_SETFL)");
exit(EXIT_FAILURE);
}
//*****************************************************
if (bind(fd1,(struct sockaddr *)&Host_info1,sizeof(Host_info1)) < 0)
{
cease("Bind",wd);
}
else
{
cout<<" Socket ID number "<<fd1<<endl;
cout<<" Bound socket..."<<endl;
}
//********** The multicast network setup ***********************
std::string input5 ="230.*.**.**";
std::string input6 = "192.***.***"; // The same host IP address as above
std::string input7 = "1500" ; // The port number to listen to for Multicast message
const char* Group_Multi_Addr = input5.data();
const char* Group_Interface_Addr = input6.data();
const char* Host_port_input = input7.data();
Group.imr_multiaddr.s_addr = inet_addr(Group_Multi_Addr);
Group.imr_interface.s_addr = inet_addr(Group_Interface_Addr);
Host_info2.sin_family = AF_INET;
Host_info2.sin_addr.s_addr = INADDR_ANY;
Host_info2.sin_port = htons((uint16_t)stoi(Host_port_input,nullptr,0));
//***** The second socket *******
fd2 = socket(AF_INET, SOCK_DGRAM, 0);
if(fd2 < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening the datagram socket...OK.\n");
int reuse = 1;
if(setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
close(fd2);
cease("Setting SO_REUSEADDR error", wd);
}
else
printf("Setting SO_REUSEADDR...OK.\n");
if(bind(fd2, (struct sockaddr*)&Host_info2, sizeof(Host_info2)))
{
close(fd2);
cease("Binding datagram socket error",wd);
}
else
printf("Binding datagram socket...OK.\n");
if(setsockopt(fd2, IPPROTO_IP, IP_ADD_MEMBERSHIP,(char *)&Group,sizeof(Group)) < 0)
{
perror("Adding multicast group error");
close(fd2);
exit(1);
}
else
printf("Adding multicast group...OK.\n");
StructArg.Hinfo1= Host_info1;
StructArg.Hinfo2= Host_info2 ;
StructArg.Rinfo= Remote_info ;
StructArg.sock1=fd1;
StructArg.sock2=fd2;
fd_set readfds ,rd_fds;
struct timeval tv;
// clear the set ahead of time
FD_ZERO(&readfds);
// add our descriptors to the set
FD_SET(StructArg.sock1, &readfds);
FD_SET(StructArg.sock2, &readfds);
nls = StructArg.sock2 + 1;
char Recv_buffer[125];
char TX_buffer[125];
memset((char *)&Recv_buffer,'0',sizeof(Recv_buffer));
memset((char *)&TX_buffer,'0',sizeof(TX_buffer));
int lenremote(sizeof(StructArg.Rinfo));
ssize_t rs, rs2;
uint8_t MsgSize;
uint8_t MsgID;
int rst;
do
{
do{
rd_fds=readfds;
tv.tv_sec = 0;
tv.tv_usec = 50;
rst = select(nls, &rd_fds, NULL, NULL, &tv);
}while(rst ==-1 && erno==EINTR);
if (rst < 0)
{
perror("select"); // error occurred in select()
}
else
{
// one or both of the descriptors have data
if (FD_ISSET(StructArg.sock1, &rd_fds))
{
rs = recvfrom(StructArg.sock1,....,...,0,...,...) ;
if ( rs > 0 )
{
Do periodic routine work using this unicast socket
}
}
if (FD_ISSET(StructArg.sock2, &rd_fds))
{
rs2 = recv(StructArg.sock2,&Recv_buffer,sizeof(Recv_buffer),0);
if ( rs2 > 0 )
{
send some data to StructArg.sock1
}
}
// THIS IS WHERE I RECEIVE THE MULTICAST FROM PROGRAM 2, AND I DO COMPUTATUIONS , THEN RESPOND USING SOCKET 1 ABOVE (sendto using socket information of the other socket)
}
while(1);
return 0;
}
I am not sure where the problem lies...is it in the configuration of the IP/ports or in Select (i doubt it because it works when in different computers) ???
Goal:
I need to be able to ping a network switch to determine whether or not it is available. This is meant to tell the user that either the network cabling is unplugged, the network switch is unavailable, or some other problem lies within the network communication pathway. I realize this is not a comprehensive diagnosis tool, but something is better than nothing.
Design:
I planned on using ICMP with raw sockets to send five (5) ping messages to a particular address in IPv4 dot-notation. I will setup an ICMP filter on the socket and will not be creating my own IP header. Transmission of the ICMP will be through the sendto method and reception through the recvfrom method. This will occur on a single thread (though another thread can be used to break transmission and reception apart). Reception of a message will further be filtered by matching the ID of the received message to the ID that was transmitted. The ID stored will be the running process ID of the application. If an ICMP_ECHOREPLY message is received and the ID of the message and the stored ID match, then a counter is incremented until five (4) has been reached (the counter is zero-based). I will attempt to send a ping, wait for its reply, and repeat this process five (5) times.
The Problem:
After having implemented my design, whenever I ping a particular valid network address (say 192.168.11.15) with an active network participant, I receive ICMP_ECHOREPLY messages for each of the five (5) pings. However, whenever I ping a valid network address (say 192.168.30.30) with inactive network participants (meaning no device is connected to the particular address), I get one (1) ICMP_DEST_UNREACH, and four (4) ICMP_ECHOREPLY messages. The ID in the reply messages match the ID stored within the software. Whenever I perform a 'ping 192.168.30.30' from the commandline, I get 'From 192.168.40.50 icmp_seq=xx Destination Host Unreachable'. Am I not supposed to be receiving ICMP_DEST_UNREACH messages instead of ICMP_ECHOREPLY messages?
The Code:
Ping.h:
#include <netinet/in.h>
#include <linux/ip.h>
#include <linux/ipmc.h>
#include <arpa/inet.h>
#include <cstdio>
#include <cstdlib>
#include <stdint.h>
#include <time.h>
#include <errno.h>
#include <string>
#include <cstring>
#include <netdb.h>
class Ping
{
public:
Ping(std::string host) : _host(host) {}
~Ping() {}
void start()
{
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(sock < 0)
{
printf("Failed to create socket!\n");
close(sock);
exit(1);
}
setuid(getuid());
sockaddr_in pingaddr;
memset(&pingaddr, 0, sizeof(sockaddr_in));
pingaddr.sin_family = AF_INET;
hostent *h = gethostbyname(_host.c_str());
if(not h)
{
printf("Failed to get host by name!\n");
close(sock);
exit(1);
}
memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
// Set the ID of the sender (will go into the ID of the echo msg)
int pid = getpid();
// Only want to receive the following messages
icmp_filter filter;
filter.data = ~((1<<ICMP_SOURCE_QUENCH) |
(1<<ICMP_DEST_UNREACH) |
(1<<ICMP_TIME_EXCEEDED) |
(1<<ICMP_REDIRECT) |
(1<<ICMP_ECHOREPLY));
if(setsockopt(sock, SOL_RAW, ICMP_FILTER, (char *)&filter, sizeof(filter)) < 0)
{
perror("setsockopt(ICMP_FILTER)");
exit(3);
}
// Number of valid echo receptions
int nrec = 0;
// Send the packet
for(int i = 0; i < 5; ++i)
{
char packet[sizeof(icmphdr)];
memset(packet, 0, sizeof(packet));
icmphdr *pkt = (icmphdr *)packet;
pkt->type = ICMP_ECHO;
pkt->code = 0;
pkt->checksum = 0;
pkt->un.echo.id = htons(pid & 0xFFFF);
pkt->un.echo.sequence = i;
pkt->checksum = checksum((uint16_t *)pkt, sizeof(packet));
int bytes = sendto(sock, packet, sizeof(packet), 0, (sockaddr *)&pingaddr, sizeof(sockaddr_in));
if(bytes < 0)
{
printf("Failed to send to receiver\n");
close(sock);
exit(1);
}
else if(bytes != sizeof(packet))
{
printf("Failed to write the whole packet --- bytes: %d, sizeof(packet): %d\n", bytes, sizeof(packet));
close(sock);
exit(1);
}
while(1)
{
char inbuf[192];
memset(inbuf, 0, sizeof(inbuf));
int addrlen = sizeof(sockaddr_in);
bytes = recvfrom(sock, inbuf, sizeof(inbuf), 0, (sockaddr *)&pingaddr, (socklen_t *)&addrlen);
if(bytes < 0)
{
printf("Error on recvfrom\n");
exit(1);
}
else
{
if(bytes < sizeof(iphdr) + sizeof(icmphdr))
{
printf("Incorrect read bytes!\n");
continue;
}
iphdr *iph = (iphdr *)inbuf;
int hlen = (iph->ihl << 2);
bytes -= hlen;
pkt = (icmphdr *)(inbuf + hlen);
int id = ntohs(pkt->un.echo.id);
if(pkt->type == ICMP_ECHOREPLY)
{
printf(" ICMP_ECHOREPLY\n");
if(id == pid)
{
nrec++;
if(i < 5) break;
}
}
else if(pkt->type == ICMP_DEST_UNREACH)
{
printf(" ICMP_DEST_UNREACH\n");
// Extract the original data out of the received message
int offset = sizeof(iphdr) + sizeof(icmphdr) + sizeof(iphdr);
if(((bytes + hlen) - offset) == sizeof(icmphdr))
{
icmphdr *p = reinterpret_cast<icmphdr *>(inbuf + offset);
id = ntohs(p->un.echo.id);
if(origid == pid)
{
printf(" IDs match!\n");
break;
}
}
}
}
}
}
printf("nrec: %d\n", nrec);
}
private:
int32_t checksum(uint16_t *buf, int32_t len)
{
int32_t nleft = len;
int32_t sum = 0;
uint16_t *w = buf;
uint16_t answer = 0;
while(nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if(nleft == 1)
{
*(uint16_t *)(&answer) = *(uint8_t *)w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
answer = ~sum;
return answer;
}
std::string _host;
};
main.cpp:
#include "Ping.h"
int main()
{
// Ping ping("192.168.11.15");
Ping ping("192.168.30.30");
ping.start();
while(1) sleep(10);
}
In order to compile, just type 'g++ main.cpp -o ping' into the command-line of a Linux box, and it should compile (that is, if all of the source code is installed).
Conclusion:
Can anyone tell me why I am receiving one (1) ICMP_DEST_UNREACH and four (4) ICMP_ECHOREPLY messages from a device that isn't on that particular network address?
NOTE: You can change the network IP address from the main.cpp file. Just change the IP to a device that actually exists on your network or a device that doesn't exist on your network.
I'm also not interested in criticisms about coding style. I know it isn't pretty, has 'C' style casting mixed with C++ casts, has poor memory management, etc, but this is only prototype code. It isn't meant to be pretty.
Ok i found the error. Look at this two lines.
int bytes = sendto(sock, packet, sizeof(packet), 0, (sockaddr *)&pingaddr, sizeof(sockaddr_in));
bytes = recvfrom(sock, inbuf, sizeof(inbuf), 0, (sockaddr *)&pingaddr, (socklen_t *)&addrlen);
both functions uses pingaddr pointer as parameter, but this should avoided because in the sendto() function is used to point the destination IP of the icmp packet but in the recvfrom() is used to get back the IP of the host that's replying.
Let's say pingaddr is set with an IP not reachable. After your first ICMP_REQUEST the first gateway will reply to you with a ICMP_DEST_UNREACH and... here comes the error... when recvfrom is called, pingaddr structure will be overwritten with the IP of the gateway.
SO... from the second ping you'll be pointing to the gateway IP that, obviously, exists and will reply with a ICMP_ECHOREPLY.
SOLUTION:
avoid pass the same sockaddr_in structure pointer to both sendto() and recvfrom().
I've been trying to send a packet from a client to a server via sockets. With the help of some of the tips I have made quite bit of progress in my code. However, the server only receives eight bytes from the client and prints them on the console whereas at my client side, It seems that it has sent everything.
Now I am not sure whether the problem is at the sending side or the receiving side. My hunch is that something is wrong at my client side. Could someone please help in verifying my assumption?
Client code:
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
data_struct client_data;
struct packet
{
long int srcID;
long int destID;
int pver;
int profiles;
int length;
long int data;
};
if (argc < 3) {
fprintf(stderr,"usage: %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]); //Convert ASCII to integer
sockfd = socket(AF_INET, SOCK_STREAM, 0); // socket file descriptor
if (sockfd < 0)
error("ERROR DETECTED !!! Problem in opening socket\n");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR DETECTED !!!, no such server found \n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr)); //clear the memory for server address
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
printf("Client 1 trying to connect with server host %s on port %d\n", argv[1], portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR in connection");
printf("SUCCESS !!! Connection established \n");
char buffer[256];
struct packet *pkt = (struct packet *) buffer;
char *payload = buffer + sizeof(struct packet);
long double packet_size;
printf("Started Creating packet\n");
pkt->srcID = 01;
pkt->destID = 02;
pkt->pver = 03;
pkt->profiles = 01;
pkt->length = 16;
pkt->data = 1; 2; 3; 4; 5; 6; 7; 8;
{
if (send(sockfd,pkt,sizeof(packet_size),0) <0)
printf ("error\n");
else
printf ("packet send done");
}
return 0;
}
Server code:
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
struct sockaddr_in serv_addr, cli_addr;
int n;
char wish;
long int SrcID;
long int DestID;
int Pver;
int Profiles;
long int Data;
int Length;
char bytes_to_receive;
int received_bytes;
struct packet
{
long int srcID;
long int destID;
int pver;
int profiles;
int length;
long int data;
};
if (argc < 2) {
fprintf(stderr,"usage: %s port_number1",argv[0]);
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR DETECTED !!! Problem in opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR DETECTED !!! There was a problem in binding");
listen(sockfd, 10);
clilen = sizeof(cli_addr);
printf("Server listening on port number %d...\n", serv_addr.sin_port);
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR DETECTED !!! the connection request was not accepted");
char buffer[256];
struct packet *pkt = (struct packet *) buffer;
char *payload = buffer + sizeof(struct packet);
long double packet_size;
bytes_to_receive = sizeof(packet_size);
received_bytes = 0;
int rc =0;
while ((rc = recv(newsockfd,pkt,sizeof(packet_size),0)) > 0)
{
received_bytes+=rc;
SrcID = pkt->srcID;
DestID = pkt->destID;
Pver = pkt->pver ;
Profiles = pkt->profiles;
Length = pkt->length;
Data = pkt->data;
printf("Data Received from Client_1 are :\n");
printf("Source ID: %ld\n", SrcID);
printf("Destination ID: %ld\n", DestID);
printf("profile Version: %d\n", Pver);
printf("No of Profiles: %d\n", Profiles);
printf("Length: %d\n", Length);
printf("data : %ld\n", Data);
}
if (rc == 0)
{
printf("Connection closed by Server\n");
printf("Bytes received: %d\n",received_bytes);
}
if (rc == -1)
{
perror("recv");
}
{
if (close(newsockfd) == -1) {
error("Error closing connection with client 1");
}
printf("Connection with client 1 has been closed\n");
}
return 0;
}
The output that I see on the client's console is:
Client Side: Client 1 trying to connect with server host 130.191.166.230 on port 1234
SUCCESS !!! Connection established
Started Creating packet
packet send done
and on the server's console I see:
Server Side: Data Received from Client_1 are :
Source ID: 1
Destination ID: 2
profile Version: 0
No of Profiles: 1074462536
Length: 0
data : 0
Connection closed by Server
Bytes received: 8
Connection with client 1 has been closed
First of all
recv(newsockfd,pkt,sizeof(packet_size),0)) /* What is packet_size ? */
recv(newsockfd,pkt,sizeof(struct packet),0)) /* You probably mean this. */
That might solve your problems, but there are a few issues with the way you are using TCP sockets.
But at my client side, it prints that it has sent everything
Where ? I don't see you actually checking the number of bytes sent. send(2) can return after sending less that you asked it to.
It shows me that only 8 bytes were sent by Client and prints them out.
TCP is a stream-oriented protocol. You send bytes and they arrive, in the same order. So when you recv(2) something, you might get less (or more than you wrote). So, the following can be true:
client:
send 100 bytes
send 400 bytes
server:
recv 50 bytes
recv 150 bytes
recv 250 bytes
recv 50 bytes
The number of send and recv calls need not be identical when using TCP.
When you call send the function returns the number of bytes actually sent and this number can be less than the number of bytes you wanted to send. So every time you want to send something there must be a loop like the following
bool sendBuffer(SOCKET s, unsigned char *buf, int size)
{
while (size > 0)
{
int sz = send(s, buf, size,0);
if (sz < 0) return false; // Failure
size -= sz; // Decrement number of bytes to send
buf += sz; // Advance read pointer
}
return true; // All buffer has been sent
}
and a similar loop must be done when receiving (in other words recv can return less bytes than what you are asking for).
If you don't make these loops the risk is that everything apparently will work anyway (until the size of an ethernet packet) when you work on your local machine or even over a LAN, but things will not work when working across the internet.
Note also that as other answers pointed out you asked to send sizeof(packet_size) i.e. the number of bytes required to store that variable, not the size of the structure.
There is an informal rule that nobody is allowed to write any software that uses TCP until they memorize this sentence and can fully explain what it means: "TCP is a byte-stream protocol that does not preserve application message boundaries."
What that means is that TCP only ensures that you get out the same bytes you put in and in the same order. It does not "glue" the bytes together in any way.
Before you write any code that uses TCP, you should either use a protocol that is already designed (such as IMAP or HTTP) or design one yourself. If you design one yourself, you should write out a protocol specification. It should specifically define what a protocol-level message will consist of at the byte level. It should specifically state how the receiver finds the ends of messages, and so on.
This may seem a little silly for simple applications, but trust me, it will pay off massively. Otherwise, it's almost impossible to figure out why things aren't work because if the server and client don't quite get along, there's no arbiter to say what's right.
I don't specialise in socket programming but there are a few things I've noticed. As far as I'm aware, I don't think you can send structs over sockets that easily. You may wish to consider a different method.
NB, when using send/recv you're also determing the sizeof packet_size, and not the sizeof the struct.
Googling brought up this about sending structs over sockets: http://ubuntuforums.org/showthread.php?t=613906