client socket unable to receive data using poll/select - c

/* SEND FUNC. */
int mysend(unsigned char *buffer, int len) {
int sock,ret;
int status,flags;
struct sockaddr_in6 servaddr;
int opt = 1;
char *addr = "1101::1";
sock = socket(AF_INET6,SOCK_DGRAM,0);
if (sock < 0)
return -1;
if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )
return -1;
flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags|O_NONBLOCK);
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(61616);
status = inet_pton(AF_INET6, addr, &servaddr.sin6_addr);
if (status <= 0) {
perror("inet_pton");
return -1;
}
/* send message to server */
status = sendto(sock, buffer, len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (status < 0) {
perror("sendto");
return -1;
}
close(sock);
printf("MESSAGE SENT SUCCESSFULLY\n");
return 0;
}
/* RECEIVE FUNC. */
int myrcv() {
int sock,ret;
int status,len,rx_bytes;
int timeout,nfds =1;
struct sockaddr_in6 servaddr;
struct timeval wait;
unsigned char rxbuff[1024];
char *rcv;
char *addr = "1101::1";
fd_set rd;
struct pollfd *fds;
sock = socket(AF_INET6,SOCK_DGRAM,0);
if (sock < 0)
return -1;
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(61616);
status = inet_pton(AF_INET6, addr, &servaddr.sin6_addr);
if (status <= 0)
return -1;
bind(sock,(struct sockaddr *)&servaddr,sizeof(servaddr));
timeout = (1* 1000);
wait.tv_sec = 10;
wait.tv_usec = 0;
len = sizeof(servaddr);
fds->fd = sock;
fds->events = POLLIN;
for(;;) {
//FD_ZERO(&rd);
//FD_SET(sock,&rd);
printf("Waiting for data....\n");
ret = poll(fds,nfds,timeout);
//ret = select(1,&rd,NULL,NULL,&wait);
if(ret < 0)
break;
if(fds->revents == 0)
printf("revents 0 %d\n",ret);
if(ret == 0)
continue;
memset(rxbuff,0,1024);
//if(FD_ISSET(sock,&rd)) {
printf("receiving message\n");
rx_bytes = recvfrom(sock,rxbuff,1024,0,(struct sockaddr *)&servaddr,&len);
memcpy(rcv,rxbuff,rx_bytes);
//}
}
close(sock);
return 0;
}
int main()
{
/* call mysend() periodically using sigaction() */
/* create a thread that continuously monitors(calls myrcv()) for incoming data */
return 0;
}
I'm unable to receive the packets from the server, but I could see the packets in the tcpdump output. Above are the sample client code snippets, which tries to receive and send the data from/to the server. The scenario is: the client needs to send data periodically to server and should also be able to receive any data from the server.
I have tried using both poll and select methods but failed to receive. Please let me know if I'm missing anything. Thanks for your support.

The problem you have with receiving is that you need to bind the receiving socket to the local port.
You also have other things that can be improved, like creating a single socket for both sending and receiving and using SO_REUSEADDR on the sending socket (not needed on a write-only socket).
What you should do is:
Create socket
Set socket options
Bind to local address (Use IN6ADDR_ANY_INIT to bind to all interfaces)
Write to server
Poll for reply

Several things:
Your receive function (myrcv) isn't specifying a listen port via the bind() call. That's the most likely problem. Ditto for your send function, although a port is chosen randomly for you.
In you myrcv() function, I don't see where you have actually initialized fds or nfsd prior to calling poll().
Re-opening and closing the socket on each call to mysend() looks problematic. If you are expecting the server to send back to the same client on the same port it received the message on, chances are high you have already closed the socket. You should just open one socket for both sending and receiving. You can share the same socket between your send thread and your receive thread.

Related

Reading UDP packets with several clients

I have an application installed locally (not developed by me), which broadcasts UDP packets every second.
Reading the packets from my application (developed in C++ in Windows) which also is locally installed, works fine.
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOK = WSAStartup(version, &data);
SOCKET serverIn = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = INADDR_ANY;
serverHint.sin_family = AF_INET;
serverHint.sin_port = htons(UDP_RECEIVE_PORT);
bind(serverIn, (sockaddr*)&serverHint, sizeof(serverHint));
sockaddr_in client;
int clientSize = sizeof(client);
int RECIEVE_BUFFER_SIZE = 65507;
char* recieveBuffer = new char[RECIEVE_BUFFER_SIZE];
while(updating)
{
int bytesIn = recvfrom(serverIn, recieveBuffer, RECIEVE_BUFFER_SIZE, 0, (sockaddr*)&client, &clientSize);
}
closesocket(serverIn);
WSACleanup();
But I recently noticed while I was testing some code, while my app was running, that the bind(...)
function returned an error code of 10048 (WSAEADDRINUSE). Hence, it seems the first client bound to listen for the UDP packets is the only one who can listen, and the other clients is unable to read the broadcasted UDP packets.
So then I added the SO_REUSEADDR option before calling the bind(...) function to be able to bind successfully to the socket:
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
setsockopt((SOCKET)serverIn, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen);
That works, but the recvfrom(...) function then does not recieve any data at all! I guess it waits for the other client to close its socket.
Next solution is to initialize the socket with SOCK_RAW instead.
The above option SO_REUSEADDR is now not needed, and remove it:
SOCKET serverIn = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
This works, I can read the data now! Though, Windows now requires the adminstrator rights for my application. Also I do recieve the UDP information in the data which I do not need.
Is there any better method to do this without requiring administrator rights, any possibility to discard the header information in the buffer?
Below is a little program I wrote to demonstrate that IPv4 UDP broadcast can and does work as expected under Windows (i.e. without requiring raw-sockets or Administrator privileges).
Run it with the command line argument "server" and it will send out one broadcast UDP packet per second.
Then also run several more instances of the same program, with no command line arguments, to receive the UDP packets and print a line of text to stdout whenever they do. The expected behavior should look like this:
As for why it's not working for you -- one possible guess is that your UDP-packet-sending program is actually sending out unicast UDP packets rather than broadcast. If that's the case, then I would expect that only one client program would receive packets (even if multiple clients are bound to the same port). A network trace tool like Wireshark might be able to help you determine if the UDP packets being sent are broadcast or unicast.
Anyway, here's the code:
#include <stdio.h>
#include <ws2tcpip.h>
#pragma comment(lib,"WS2_32")
static int BindUDPSocket(SOCKET sock, unsigned short port, bool allowPortSharing)
{
if (sock == INVALID_SOCKET) return -1;
if (allowPortSharing)
{
const BOOL trueValue = true;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &trueValue, sizeof(trueValue)) < 0) return -1;
}
struct sockaddr_in bindAddr; memset(&bindAddr, 0, sizeof(bindAddr));
bindAddr.sin_family = AF_INET;
bindAddr.sin_addr.s_addr = INADDR_ANY; // aka 0.0.0.0
bindAddr.sin_port = htons(port);
return bind(sock, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
}
int main(int argc, char ** argv)
{
WSADATA data;
WORD version = MAKEWORD(2, 2);
(void) WSAStartup(version, &data);
const unsigned short TEST_PORT = 12345;
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock<0) {printf("socket() failed\n"); exit(10);}
if ((argc > 1)&&(strcmp(argv[1], "server") == 0))
{
if (BindUDPSocket(sock, 0, false)<0) {printf("BindUDPSocket() failed for server\n"); exit(10);}
const BOOL allowBroadcast = true;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *) &allowBroadcast, sizeof(allowBroadcast)) < 0)
{
printf("setsockopt(SO_BROADCAST) failed\n");
exit(10);
}
const char buf[] = {0x01, 0x02, 0x03, 0x04}; // dummy data
struct sockaddr_in toAddr; memset(&toAddr, 0, sizeof(toAddr));
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = INADDR_BROADCAST; // aka 255.255.255.255
toAddr.sin_port = htons(TEST_PORT);
printf("Sending outgoing broadcast UDP sockets on port %u, once per second\n", TEST_PORT);
while(true)
{
if (sendto(sock, buf, sizeof(buf), 0, (const sockaddr *) &toAddr, sizeof(toAddr)) == sizeof(buf))
{
printf("Sent %zu bytes of broadcast UDP data\n", sizeof(buf));
}
else printf("sendto() failed!\n");
Sleep(1000); // wait 1 second
}
}
else
{
if (BindUDPSocket(sock, TEST_PORT, true)<0) {printf("BindUDPSocket() failed for client\n"); exit(10);}
printf("Waiting to receive incoming broadcast UDP sockets on port %u\n", TEST_PORT);
while(true)
{
char buf[1024];
const int ret = recv(sock, buf, sizeof(buf), 0L);
printf("Received %i bytes of incoming UDP data\n", ret);
}
}
}

How to use IO multiplexing technology to improve server concurrency performance?

I want to make a server software similar to Apache on windows platforms.
. The client sends data to the specified server port and the server responds accordingly. In order to improve the client access speed, I want to use "select" to improve the performance of the server, but there are many problems in the use process.
Here is my code;
Function "create_server"
This function is used to create the server Socket and set it to non-blocking.
int create_server(char*ip_address,int port) {
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if(WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
int server_socket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
int ret = -1;
struct sockaddr_in addr;
if (server_socket == -1) {
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.S_un.S_addr= INADDR_ANY;
ret = bind(server_socket,(LPSOCKADDR)&addr,sizeof(addr));
if (ret == -1) {
perror("bind error!");
return -2;
}
listen(server_socket,5);
SetBlock(server_socket, 0);
return server_socket;}
Function "SetBlock"
This function is used to change the socket blocking mode.
int SetBlock(int sock, int isblock){
int re = 0;
unsigned long ul = 0;
if (!isblock) ul = 1;
re = ioctlsocket(sock, FIONBIO, (unsigned long*)& ul);
if (re != 0) return 0;
return 1;
}
Function "main"
int main() {
int s = create_server("127.0.0.1",6666);
int client_socket = -1;
struct sockaddr_in clientaddr;
int addrlen = sizeof(clientaddr);
char buf[1025];
int buffersize=1,result=0;
int isread = 0;
fd_set server;
struct timeval timeout;
int fd = 0;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
FD_ZERO(&server);
FD_SET(s, &server);
while (1) {
result = select(FD_SETSIZE, &server, NULL, NULL, NULL);
if (result < 1) {
perror("error!");
exit(1);
}
if (FD_ISSET(s, &server)) {
//if server can be readable and written do this
client_socket = accept(s, (struct sockaddr*) & clientaddr, &addrlen);
while (buffersize > 0) {
buffersize = recv(client_socket, buf, 1024, 0);
buf[buffersize] = '\0';
printf("%s", buf);
if (buffersize < 1024) {
break;
}
}
buffersize = 1;
}
}
return 0;}
As you know, TCP takes some time to establish a connection. I want to use the "select" function to reduce the setup time of multi-client connections. I think the function "accept" is the process of establishing connection between client and server, but how to use IO multiplexing in this process, please help me.
the use of select() will delay all client connections to the server.
suggest a sequence similar to:
create a thread pool
create a sockaddr_in
sock_t serverSock = socket()
bind()
listen()
while( 1 )
{
sock_t clientSock = accept( serverSock, ... )
pass clientSock to available thread and mark thread as 'busy'
}
That way, the communication with a client does not 'hang' on a select(), nor a accept()
in each thread:
while(1)
{
wait until thread marked as 'busy'
sock_t mySocket = passedSocket
perform all communication with the specific client
close( mySocket );
mark thread as 'idle'
}

TCP/IP in C not working

I am having trouble getting my TCP/IP connection between my client and server working.
Here is the server code -
int main() {
int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */
unsigned short echoServPort; /* Server port */
struct sockaddr_in echoServAddr; /* Local address */
struct sockaddr_in echoClntAddr; /* Local address */
pid_t processID; /* Process ID from fork()*/
unsigned int childProcCount = 0; /* Number of child processes */
unsigned int clntLen;
unsigned int recvMsgSize;
echoServPort = 22;
if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
printf("Socket failed");
}
echoServAddr.sin_family = AF_INET; //Internet address family
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); //Any incoming interface
echoServAddr.sin_port = htons(echoServPort); // Local port
if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0){
printf("bind failed");
}
if (listen(servSock, MAXPENDING) < 0){
printf("listen() failed");
}
clntLen = sizeof(echoClntAddr);
if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen))<0){
printf("accept() failed");
}
if ((recvMsgSize = recv(clntSock, buf, 1024, 0)) < 0){
printf("recv() failed");
}
/* Send received string and receive again until end of transmission */
while (recvMsgSize > 0) { /* zero indicates end of transmission */
printf("%d", recvMsgSize);
if (send(clntSock, buf, recvMsgSize, 0) != recvMsgSize){
//printf(“send() failed”);
}
if ((recvMsgSize = recv(clntSock, buf, 1024, 0)) < 0){
//printf(“recv() failed”);
}
}
sleep(60);
}
}
return EXIT_SUCCESS;
}
And the client code, which is a CGI application.
int main(void) {
int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */
unsigned short echoServPort; /* Server port */
struct sockaddr_in echoServAddr; /* Local address */
struct sockaddr_in echoClntAddr; /* Local address */
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
/*pid_t processID; Process ID from fork()
unsigned int childProcCount = 0; Number of child processes
unsigned int clntLen;*/
//char echoservIP = "10.0.0.2";
printf("Content-type: text/html\n\n");
puts("<HTML>");
puts("<BODY>");
echoServPort = 22;
servSock = 22;
clntSock = 22;
puts("<br>");
if ((clntSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
printf("socket() failed");
}
echoServAddr.sin_family = AF_INET; //Internet address family
echoServAddr.sin_addr.s_addr = inet_addr("10.0.0.2"); //Server IP address
echoServAddr.sin_port = htons(echoServPort); //Server port
echoClntAddr.sin_addr.s_addr = inet_addr("10.0.0.1");
if (connect(clntSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0){
printf("connect() failed\n");
}
int clntLen;
clntLen = sizeof(echoClntAddr);
if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen))<0){
printf("accept() failed\n");
}
char echoString[4] = "helo";
int echoStringLen;
echoStringLen = strlen(echoString); //Determine input length
//Send the string to the server
if (send(clntSock, echoString, echoStringLen, 0) != echoStringLen){
printf("send() sent a different number of bytes than expected");
}
puts("<p>Hello <b>CGI</b</p>");
puts("</BODY>");
puts("</HTML>");
return EXIT_SUCCESS;
}
When debugging, the problem occurs on the client side at the line
if ((clntSock=accept(servSock,(struct sockaddr
*)&echoClntAddr,&clntLen))<0){
printf("accept() failed\n");
}
And at
if(send(clntSock, echoString, echoStringLen, 0) != echoStringLen){
printf("send() sent a different number of bytes than expected");
}
I get the output
<HTML>
<BODY>
<br>
accept() failed
send() sent a different number of bytes than expected<p>Hello
<b>CGI</b</p>
Need help fixing this!, thanks.
You don't need to call accept() on the client - you just need to connect.
And
char echoString[4] = "helo";
is wrong. It's not NUL-terminated. Just do
char echoString[] = "helo";
If accept fails you shouldn't be proceeding with other operations on socket like recv. TCP connections is not in place for you to proceed in data exchange between server and client. You need to handle error conditions with out fail.
On the client side you have a custom error message on send. That does not help. Usually, partial sends are not common. Hence your print `sent a different number of bytes than expected' can be misleading. You need to find the real reason.
Calling accept in client code is not needed. Its the server which accepts and clients the ones which connect
Use errno and perror like - perror("Accept Failed") on ALL of your system calls for easier debugging and remove custom prints

Simple Socket Listener and Threads Memory Leak

I have a simple C program that's supposed to listen for connections and start a new thread for each client that connects. The thread simply prints what messages it receives (for now). I followed two tutorials while making this.
It works, but I tried connecting and disconnecting repeatedly with netcat without sending any messages. Each time I connect, the program takes 8KB of memory, but it only releases 4KB when I disconnect. But I can't find the cause of the leak. It ends the thread and closes the socket every time the user disconnects. Here is all of the code involved:
void* clientFunction(void* arg) {
char receiveBuffer[RECEIVE_BUFFER_SIZE];
long receiveSize;
int clntSocket = * ((int*) arg);
while (true) {
//receive messages
receiveSize = recv(clntSocket, receiveBuffer, RECEIVE_BUFFER_SIZE, 0);
if (receiveSize <= 0) {
close(clntSocket);
return NULL;
}
printf("Received message: %s", receiveBuffer);
memset(&receiveBuffer, 0, sizeof(receiveBuffer));
}
return 0;
}
int main(int argc, const char * argv[]) {
//FOR LISTENING SOCKET =====
int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */
struct sockaddr_in serverAddress; /* Local address */
struct sockaddr_in clientAddress; /* Client address */
unsigned int clntLen; /* Length of client address data structure */
// =======
/* Create socket for incoming connections */
if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
printf("Socket creation failed!\n");
return SOCKET_ERROR;
}
memset(&serverAddress, 0, sizeof(serverAddress)); /* Zero out structure */
serverAddress.sin_family = AF_INET; /* Internet address family */
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
serverAddress.sin_port = htons(PORT); /* Local port */
if (bind(servSock, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
printf("Socket binding failed!\n");
return SOCKET_ERROR;
}
if (listen(servSock, MAXPENDING) < 0) {
printf("Socket listening failed!\n");
return SOCKET_ERROR;
}
isListening = true;
int* arg = &clntSock;
while (isListening) { //should have a timer?
/* Set the size of the in-out parameter */
clntLen = sizeof(clientAddress);
/* Wait for a client to connect */
if ((clntSock = accept(servSock, (struct sockaddr *) &clientAddress, &clntLen)) >= 0) { //??????
/* clntSock is connected to a client! */
pthread_t clientThread;
pthread_create(&clientThread, NULL, &clientFunction, (void*) arg);
}
}
return 0;
}
I put in pthread_detach(pthread_self()) right after the socket closing line, and it doesn't have the problem anymore. – sudo

socket is set with O_NONBLOCK, but it seems the calling thread still gets into sleep when sending data sometimes

Client
In fact, my client doesn't recv and process data send from server, just connects to my server.
int netif_msg_client_socket_create(char *sockpath)
{
int addrlen, retval;
int sockfd;
struct sockaddr_un serv;
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if(sockfd < 0) {
PR_ERROR(NETIF_MSG_M, " fatal failure, client msg socket, error is %s, %s %u\n", strerror(errno), __FILE__, __LINE__);
return -1;
}
/* Make client socket. */
memset (&serv, 0, sizeof (struct sockaddr_un));
serv.sun_family = AF_UNIX;
strncpy (serv.sun_path, sockpath, strlen(sockpath));
addrlen = sizeof (serv.sun_family) + strlen(serv.sun_path);
retval = connect(sockfd, (struct sockaddr*)&serv, addrlen);
if(retval < 0)
{
PR_ERROR(NETIF_MSG_M, " fatal failure, client msg connect, error is %s, %s %u\n", strerror(errno), __FILE__, __LINE__);
close(sockfd);
return -1;
}
fcntl(sockfd, F_SETFL, O_NONBLOCK);
return sockfd;
}
2.Server
But my server will try to send some data to the client continuously.
int netif_msg_server_socket_create(char *sockpath)
{
int addrlen, retval;
int sockfd;
struct sockaddr_un serv;
/* First of all, unlink existing socket */
unlink (sockpath);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if(sockfd < 0)
return -1;
fcntl(sockfd, F_SETFL, O_NONBLOCK);
/* Make server socket. */
memset (&serv, 0, sizeof (struct sockaddr_un));
serv.sun_family = AF_UNIX;
strncpy (serv.sun_path, sockpath, sizeof(serv.sun_path)-1);
addrlen = sizeof (serv.sun_family) + strlen(serv.sun_path);
//printf("sizeof(serv) == %d, addrlen == %d.\r\n", sizeof(serv), addrlen);
retval = bind (sockfd, (struct sockaddr *) &serv, addrlen);
if (retval < 0)
{
close (sockfd); /* Avoid sd leak. */
return -1;
}
retval = listen (sockfd, 20);
if (retval < 0)
{
close (sockfd); /* Avoid sd leak. */
return -1;
}
return sockfd;
}
My server uses select and accepts the connection from my client successfully.
After my server sent 412 packets(96 Bytes each), it seems the server sleeps on send.
Key codes:
printf("Try to send packet(%d bytes) to clientfd %d.\n", MSGCB_DLEN(msgcb), client->acpt_fd);
retval = send(client->acpt_fd, msgcb->data_ptr, MSGCB_DLEN(msgcb), 0);
if(retval != MSGCB_DLEN(msgcb))
{
printf("Send netif notify msg failed[%d].\n", retval);
} else {
printf("Send netif notify msg succeeded.\n");
}
After 412 packets sent to my client and "Try to ..." outputed, nothing goes on, neither "...failed" nor "...succeeded" outputs.
I use getsockopt to fetch the SO_RCVBUF and SO_SNDBUF, there are about 100000Bytes for each of them.
I don't know why, need your help, thanks!
If you want the server socket that is connected to the client to be non-blocking, then you must specifically set the new socket that is returned from accept() to be non-blocking. Your code only sets the listening socket to non-blocking.
You can perform non-blocking I/O with send using the MSG_DONTWAIT flag in the last parameter.
retval = send(client->acpt_fd, msgcb->data_ptr, MSGCB_DLEN(msgcb),
MSG_DONTWAIT);
When performing non-blocking I/O, you need to detect when the return value is signalling you to retry the operation.
if (retval < 0) {
if (errno == EAGAIN) {
/* ... handle retry of send laster when it is ready ... */
} else {
/* ... other error value cases */
}
}

Resources