Streaming engines best practice in C - c

LANG: C / ENV: Linux
I am developing a streaming engine, for now I am able to start, stop and pause the stream, but seeking is the operation that's giving me a lot of headache, I already asked a question here before and fixed some issues inside the code from the answers.
Using lseek() function, I am passing the open streaming file descriptor as first argument, plus I am using UDP for transmitting, something like the following code:
transport_fd = open(tsfile, O_RDONLY);
int offset = 1024;
off_t offsetIndicator;
if ((offsetIndicator=lseek(transport_fd, offset, SEEK_CUR))<0) printf("Error seeking\n");
Whenever I try to seek while streaming, the streaming stops and the pictures hangs.
Is there anything I should pay attention to?, i.e: like attempting to sleep() or nanosleep() after seeking into the file in order for the changes to take effect.
I couldn't find examples, papers or realted articles for best practices in such engines.
EDIT:
After testing, it seems like the file continued to stream but receiving devices on the network didn't catch the stream connection anymore, and calculating the time it took to finish after subtract seeking time, the stream seems to be finished normally.
CODE SNIPPET:
while (!completed)
{
while (/* Comparing conditions */ && !completed)
{
if (seekLck == 1) // seekLck is a semaphore to test seek signal from father process initiated by 0
{
int offset = 1024;
off_t offsetIndicator;
if ((offsetIndicator=lseek(transport_fd, offset, SEEK_CUR))<0)
printf("Error seeking\n");
nanosleep(&nano_sleep_packet, 0); //Try to sleep to see if it is still hanging, didn't work
seekLck = 0;
}
len = read(transport_fd, send_buf, packet_size);
if(len < 0) {
fprintf(stderr, "File read error \n");
completed = 1;
}
else if (len == 0)
{
fprintf(stderr, "Sent done\n");
completed = 1;
}
else
{
sent = sendto(sockfdstr, send_buf, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if(sent <= 0)
{
perror("send(): error ");
completed = 1;
}
}
}
nanosleep(&nano_sleep_packet, 0);
}
close(transport_fd);
close(sockfdstr);
free(send_buf);
printf("cleaning up\n");
return 0;
}

The main question was "Why isn't the file being streamed (Played) even when lseek() is working fine?"...
Actually nothing was wrong from the server side, but even though, the clients weren't able to continue streaming after losing the frame count (streaming ffmpeg frames, clients are getting the stream from a video scrambler).
What worked for me in this situation is getting the socket parameter and killing (in a clean way) the process that needs to be seeked in while holding the stream position, after that start a totally new stream from the seek position with the same socket parameter so it replaces the old one.
I hope this will help someone out there especially that there's no much documentation about those stuff.

Related

C sockets, Incomplete file transfer

I'm writing a C program to transfer a file of fixed size, a little over 2Mb, from a server to a client. I'm using TCP sockets on Linux and the code I wrote is the following:
Server (sender)
while (1) {
int nread = read(file, buffer, bufsize);
if (nread == 0) // EOF
break;
if (nread < 0) {
// handle errors
}
char* partial = buffer;
while (nread > 0) {
int nwrite = write(socket, partial, nread);
if (nwrite <= 0) {
// handle errors
}
nread -= nwrite;
partial += nwrite;
}
}
// file sent
shutdown(socket, SHUT_WR);
Client (receiver)
while (filesize > 0) {
nread = read(socket, buffer, bufsize);
if (nread == 0) {
// EOF - if we reach this point filesize is still > 0
// so the transfer was incomplete
break;
}
if (nread < 0) {
// handle errors
}
char* partial = buffer;
while (nread > 0) {
nwrite = write(file, partial, nread);
if (nwrite <= 0) {
// handle errors
}
nread -= nwrite;
partial += nwrite;
filesize -= nwrite;
}
}
if (filesize > 0) {
// incomplete transfer
// handle error
}
close(socket);
When testing the code on my laptop (both client and server "are" on localhost and the communication happen on the loopback interface), sometimes the client exits because read received an EOF, and not because it received all filesize bytes. Since i use a shutdown on the server, this should mean that there is no other data to read.
(Note that the server sent all the bytes and executed the shutdown correctly)
Can you explain me why this is happening?
Where are the missing bytes gone?
-----
EDIT 1 - Clarifications
Some users asked a couple of clarifications so i am posting the answers here:
The program is using TCP blocking sockets
The filesize is a fixed value and is hardcoded in both client and server.
No special socket options as, for example, SO_LINGER are enabled/used.
When the error occur, the server (sender) has already sent all the data and executed the shutdown correctly.
The error, as of today, never happened when testing the application with the client and the server on different machines (transfer over a real network interface and not a loopback interface)
EDIT 2
User Cornstalks pointed me to a really interesting article about the, non always reliable, behaviours of TCP.
The article, which is well worth a read, describe a few tricks useful when sending an unknown amount of data between TCP sockets. The tricks described are the followings:
Take advantage of the SO_LINGER option on the sender. This will help to keep the socket open, upon a call to close(2) or shutdown(2), until all the data has successfully been sent.
On the receiver, beware of pending readable data before the actual receiving loop. It could lead to an immediate reset being sent.
Take advantage of shutdown(2) to signal the receiver the the sender has done sending data.
Let the receiver know the size of the file that will be sent before actually sending the file.
Let the receiver acknowledge the sender that the receiving loop is over. This will help to prevent the sender from closing the socket too soon.
After reading the article, i upgraded my code to implement the tricks number 1 and 5.
This is how i implemented trick number 5:
Server (sender)
// sending loop ...
// file sent
shutdown(socket, SHUT_WR);
// wait acknowledgement from the client
ack = read(socket, buffer, bufsize);
if (ack < 0) {
// handle errors
}
Client (receiver)
// receiving loop..
if (filesize > 0) {
// incomplete transfer
// handle error
}
// send acknowledgement to the server
// this will send a FIN and trigger a read = 0 on the server
shutdown(socket, SHUT_WR);
close(socket);
What about tricks number 2, 3 and 4?
Trick number 2 is not needed because as soon as the server accepts the connection the application proceed to the file transfer. NO extra messages are exchanged.
Trick number 3 is already implemented
Trick number 4 is also already implemented. As mentioned earlier the file size is hardcoded, so there is no need to exchange it.
Did this solve my original problem?
NO my problem was not solved. The error is still happening, and as of today, it only happened when testing the application with both client and server on localhost.
What do you think?
Is there a way to prevent this?
You're:
assuming that read fills the buffer, even though
you're defending magnificently against write() not writing the entire buffer.
You need to do (1), and you don't need to do (2) because you're in blocking mode and POSIX assures that write() doesn't return until all the data is written.
A simple version of both loops:
while ((nread = read(inFD, buffer, 0, sizeof buffer)) > 0)
{
write(outFD, buffer, 0, nread);
}
if (nread == -1)
; // error
A more correct version would check the result of write() for errors of course.

Socket programming for multi-clients with 'select()' in C

This is a question about socket programming for multi-client.
While I was thinking how to make my single client and server program
to multi clients,I encountered how to implement this.
But even if I was searching for everything, kind of confusion exists.
I was thinking to implement with select(), because it is less heavy than fork.
but I have much global variables not to be shared, so I hadn`t considered thread to use.
and so to use select(), I could have the general knowledge about FD_functions to utilize, but here I have my question, because generally in the examples on websites, it only shows multi-client server program...
Since I use sequential recv() and send() in client and also in server program
that work really well when it`s single client and server, but
I have no idea about how it must be changed for multi cilent.
Does the client also must be unblocking?
What are all requirements for select()?
The things I did on my server program to be multi-client
1) I set my socket option for reuse address, with SO_REUSEADDR
2) and set my server as non-blocking mode with O_NONBLOCK using fctl().
3) and put the timeout argument as zero.
and proper use of FD_functions after above.
But when I run my client program one and many more, from the second client,
client program blocks, not getting accepted by server.
I guess the reason is because I put my server program`s main function part
into the 'recv was >0 ' case.
for example with my server code,
(I`m using temp and read as fd_set, and read as master in this case)
int main(void)
{
int conn_sock, listen_sock;
struct sockaddr_in s_addr, c_addr;
int rq, ack;
char path[100];
int pre, change, c;
int conn, page_num, x;
int c_len = sizeof(c_addr);
int fd;
int flags;
int opt = 1;
int nbytes;
fd_set read, temp;
if ((listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
perror("socket error!");
return 1;
}
memset(&s_addr, 0, sizeof(s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
s_addr.sin_port = htons(3500);
if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) == -1)
{
perror("Server-setsockopt() error ");
exit(1);
}
flags = fcntl(listen_sock, F_GETFL, 0);
fcntl(listen_sock, F_SETFL, flags | O_NONBLOCK);
//fcntl(listen_sock, F_SETOWN, getpid());
bind(listen_sock, (struct sockaddr*) &s_addr, sizeof(s_addr));
listen(listen_sock, 8);
FD_ZERO(&read);
FD_ZERO(&temp);
FD_SET(listen_sock, &read);
while (1)
{
temp = read;
if (select(FD_SETSIZE, &temp, (fd_set *) 0, (fd_set *) 0,
(struct timeval *) 0) < 1)
{
perror("select error:");
exit(1);
}
for (fd = 0; fd < FD_SETSIZE; fd++)
{
//CHECK all file descriptors
if (FD_ISSET(fd, &temp))
{
if (fd == listen_sock)
{
conn_sock = accept(listen_sock, (struct sockaddr *) &c_addr, &c_len);
FD_SET(conn_sock, &read);
printf("new client got session: %d\n", conn_sock);
}
else
{
nbytes = recv(fd, &conn, 4, 0);
if (nbytes <= 0)
{
close(fd);
FD_CLR(fd, &read);
}
else
{
if (conn == Session_Rq)
{
ack = Session_Ack;
send(fd, &ack, sizeof(ack), 0);
root_setting();
c = 0;
while (1)
{
c++;
printf("in while loop\n");
recv(fd, &page_num, 4, 0);
if (c > 1)
{
change = compare_with_pre_page(pre, page_num);
if (change == 1)
{
page_stack[stack_count] = page_num;
stack_count++;
}
else
{
printf("same as before page\n");
}
} //end of if
else if (c == 1)
{
page_stack[stack_count] = page_num;
stack_count++;
}
printf("stack count:%d\n", stack_count);
printf("in page stack: <");
for (x = 0; x < stack_count; x++)
{
printf(" %d ", page_stack[x]);
}
printf(">\n");
rq_handler(fd);
if (logged_in == 1)
{
printf("You are logged in state now, user: %s\n",
curr_user.ID);
}
else
{
printf("not logged in.\n");
c = 0;
}
pre = page_num;
} //end of while
} //end of if
}
} //end of else
} //end of fd_isset
} //end of for loop
} //end of outermost while
}
if needed for code explanation : What I was about to work of this code was,
to make kind of web pages to implement 'browser' for server.
I wanted to make every client get session for server to get login-page or so.
But the execution result is, as I told above.
Why is that?
the socket in the client program must be non-blocking mode too
to be used with non-blocking Server program to use select()?
Or should I use fork or thread to make multi client and manage with select?
The reason I say this is, after I considered a lot about this problem,
'select()' seems only proper for multi client chatting program... that many
'forked' or 'threaded' clients can pend to, in such as chat room.
how do you think?...
Is select also possible or proper thing to use for normal multi-client program?
If there something I missed to let my multi client program work fine,
please give me some knowledge of yours or some requirements for the proper use of select.
I didn`t know multi-client communication was not this much easy before :)
I also considered to use epoll but I think I need to understand first about select well.
Thanks for reading.
Besides the fact you want to go from single-client to multi-client, it's not very clear what's blocking you here.
Are you sure you fully understood how does select is supposed to work ? The manual (man 2 select on Linux) may be helpful, as it provides a simple example. You can also check Wikipedia.
To answer your questions :
First of all, are you sure you need non-blocking mode for your sockets ? Unless you have a good reason to do so, blocking sockets are also fine for multi-client networking.
Usually, there are basically two ways to deal with multi-clients in C: fork, or select. The two aren't really used altogether (or I don't know how :-) ). Models using lightweight threads are essentially asynchronous programming (did I mention it also depends on what you mean by 'asynchronous' ?) and may be a bit overkill for what you seem to do (a good example in C++ is Boost.Asio).
As you probably already know, the main problem when dealing with more than one client is that I/O operations, like a read, are blocking, not letting us know when there's a new client, or when a client has said something.
The fork way is pretty straighforward : the server socket (the one which accepts the connections) is in the main process, and each time it accepts a new client, it forks a whole new process just to monitor this new client : this new process will be dedicated to it. Since there's one process per client, we don't care if i/o operations are blocking or not.
The select way allows us to monitor multiple clients in one same process : it is a multiplexer telling us when something happens on the sockets we give it. The base idea, on the server side, is first to put the server socket on the read_fds FD_SET of the select. Each time select returns, you need to do a special check for it : if the server socket is set in the read_fds set (using FD_ISSET(...)), it means you have a new client connecting : you can then call accept on your server socket to create the connection.
Then you have to put all your clients sockets in the fd_sets you give to select in order to monitor any change on it (e.g., incoming messages).
I'm not really sure of what you don't understand about select, so that's for the big explaination. But long story short, select is a clean and neat way to do single-threaded, synchronous networking, and it can absolutely manage multiple clients at the same time without using any fork or threads. Be aware though that if you absolutely want to deal with non-blocking sockets with select, you have to deal extra error conditions that wouldn't be in a blocking way (the Wikipedia example shows it well as they have to check if errno isn't EWOULDBLOCK). But that's another story.
EDIT : Okay, with a little more code it's easier to know what's wrong.
select's first parameter should be nfds+1, i.e. "the highest-numbered file descriptor in any of the three sets, plus 1" (cf. manual), not FD_SETSIZE, which is the maximum size of an FD_SET. Usually it is the last accept-ed client socket (or the server socket at beginning) who has it.
You shouldn't do the "CHECK all file descriptors" for loop like that. FD_SETSIZE, e.g. on my machine, equal to 1024. That means once select returns, even if you have just one client you would be passing in the loop 1024 times ! You can set fd to 0 (like in the Wikipedia example), but since 0 is stdin, 1 stdout and 2 stderr, unless you're monitoring one of those, you can directly set it to your server socket's fd (since it is probably the first of the monitored sockets, given socket numbers always increase), and iterate until it is equal to "nfds" (the currently highest fd).
Not sure that it is mandatory, but before each call to select, you should clear (with FD_ZERO for example) and re-populate your read fd_set with all the sockets you want to monitor (i.e. your server socket and all your clients sockets). Once again, inspire yourself of the Wikipedia example.

Transferring files using UDP sockets in C

I'm fairly new to socket programming in C, so the code below may have a ton of newbie mistakes.
I'm trying to make a client-server application in which the server will transfer a file to the client using an UDP socket. Both the client and the server will run on Linux hosts. It's an assignment, so it has to be done that way. Other client-server communications may use a TCP socket, but the file transfer MUST be via UDP. The program works correctly for small files, but if I try to send a slightly larger file (say, a 600 kb text file), the client will stop receiving the packets, even though the server will send them all. Here's the file transfer part of the server code:
FILE* myFile;
long fileSize, readBytes, sentBytes, sizeCheck;
uint32_t encodedFileSize;
myFile = fopen(fileName, "rb");
if(myFile == NULL)
{
perror("Error when opening file.");
exit(1);
}
fseek(myFile, 0, SEEK_END);
fileSize = ftell(myFile);
encodedFileSize = htonl(fileSize);
rewind(myFile);
sizeCheck = 0;
write(myTCPSocket, &encodedFileSize, sizeof(encodedFileSize));
if(fileSize > 255)
{
while(sizeCheck < fileSize)
{
readBytes = fread(bufferRW, 1, 256, myFile);
sentBytes = sendto(sockfdUDP, bufferRW, readBytes, 0, (struct sockaddr*)&cli_addr, udpAddressSize);
sizeCheck += sentBytes;
}
}
else
{
readBytes = fread(bufferRW, 1, 256, myFile);
sentBytes = sendto(sockfdUDP, bufferRW, readBytes, 0, (struct sockaddr*)&cli_addr, udpAddressSize);
}
if(fileSize == sizeCheck)
{
printf("Success.\n");
}
else
{
printf("Fail.\n");
}
fclose(myFile);
fflush(stdout);
close(sockfdUDP);
As you can see, I used a TCP socket to send the client the file size. Here's the client code:
FILE *myFile;
long receivedBytes, writtenBytes, sizeCheck;
long fileSize, realFileSize;
char ack2[5] = "Ok";
sockfdUDP = socket(AF_INET, SOCK_DGRAM, 0);
read(socketTCP, &fileSize, sizeof(long));
realFileSize = ntohl(fileSize);
myFile = fopen(fileName, "wb");
if(myFile == NULL)
{
perror("Error when creating file.");
exit(1);
}
sizeCheck = 0;
if((realFileSize) > 255)
{
while(sizeCheck < (realFileSize))
{
receivedBytes = recvfrom(sockfdUDP, bufferRW, 256, 0, (struct sockaddr*)&serv_addr, &serv_addr_size);
writtenBytes = fwrite(bufferRW, 1, receivedBytes, myFile);
fflush(myFile);
sizeCheck += writtenBytes;
}
}
else
{
receivedBytes = recvfrom(sockfdUDP, bufferRW, 256, 0, (struct sockaddr*)&serv_addr, &serv_addr_size);
fwrite(bufferRW, 1, receivedBytes, myFile);
fflush(myFile);
}
if(realFileSize == sizeCheck)
{
printf("Success.");
}
else
{
printf("Fail.");
}
fclose(myFile);
close(sockfdUDP);
The "bufferRW" buffer was originally declared as char bufferRW[256] and passed to the function as an argument. Same goes for other undeclared variables.
Like I said before, the server will (apparently) send the whole file without any issues. However, the client will stop receiving packets after it's written about 423936 bytes (this may vary between executions). It'll just stay at the recvfrom line, without reading anything.
Now, I'm sure the problem is not being caused by a faulty connection since I'm testing both processes on the same host. And before you ask "What is it with the 256 byte packet size?", there's this weird bug that will throw me a segmentation fault on the realFileSize = ntohl(fileSize); client line if I use a buffer size of, say, 1500.
Could you please tell me what am I missing here?
EDIT: I'm trying with different file sizes now. It seems to handle files larger than 256 bytes without issue (it enters and exits the while loops correctly on both client and server), but the client will start having problems when the file is bigger than, say, 300 kb.
EDIT 2: I just debugged the program. Apparently, the server sends the entire file before the client can even enter its while loop.
EDIT 3: I think I know what's causing the issue. It seems like if the server sends a bunch of packets before the client starts reading, the client will read up to 278 packets, regardless of their size. If I try sending, say, 279 before the client starts reading it won't read the 279th packet. So if the server sends its packets fast enough, the number of packets that the client hasn't read yet will exceed 278 and the client won't finish reading all of the packets. Any ideas on how to fix this?
long* fileSize declared a pointer to a long, but in your code, it's pointing nowhere. In fact, it's pointing to a random address. You should declare it as long fileSize, and call read(socketTCP, &fileSize, sizeof(long)) instead.
You should check the return value of read, write, etc, to guarantee they did not fail. For example, sendto returns -1 on error. You're ignoring this, and incrementing sizeCheck with this value anyway.
UDP is not a reliable protocol for file transfers, but if you cannot do without it, you better implement some controls that TCP already gives you for free, like packet reordering, data checksum, etc. And that can be a very complex task by itself.
Compile your code with -Wall -Wextra. The compiler will give you hints about what could be potentially wrong. I see you're still using *fileSize in a comparison, which is clearly wrong.
After you fix the *fileSize issue, your loop-condition is still using the wrong value (due to fileSize = ntohl(fileSize)). You need to store this value in another variable, or change your loop-condition to use the real file size.
Regarding your EDIT 3, you need to somehow synchronise your client & server, so they can start the transmission at the same time. However, a sender that is much faster than the receiver will still cause packet loss. To solve this, you'll also need to implement packet acknowledgement, and retransmit a packet if the sender doesn't receive an ACK for a respective sent packet after a timeout. This is something TCP already does for you.
A simpler (but not completely reliable) way, would be to slow down the sending process a bit - maybe using nanosleep between each call to sendto.

Unable to receive the last socket data sent using the MSG_MORE flag

server side code:
dirp=opendir(path);
if(dirp==NULL)
{
strcpy(err,"error:");
strcat(err,strerror(errno));
send(fd,err,sizeof(err),0);
}
else
{
printf("\nstream opened\n");
while((dp=readdir(dirp))!= NULL)
{
r=send(fd,dp->d_name,100,MSG_MORE);
if(r<0)
perror("\nsend:");
printf("\n%s",dp->d_name);
}
}
client:
while(recv(mainsocket,lsbuf,100,0)>0)
{
printf("\n %s",lsbuf);
bzero(lsbuf,sizeof(lsbuf));
}
the server side is printing all the filenames on the standard output,but on the client side the client is not receiving the last filename and program is getting blocked at that point
The problem is with the send syscall. You call it with MSG_MORE flag that means the more data will follow and send waits for more data without actually sending. The last chunk of data you should send without this flag. Thus your server side should look like:
dp = readdir(dirp);
if (dp != NULL)
{
/* each time check whether there are more data */
while((dp_next = readdir(dirp))!= NULL)
{
r = send(fd, dp->d_name, 100, MSG_MORE);
if (r < 0) {
perror("\nsend");
}
printf("\n%s",dp->d_name);
dp = dp_next;
}
/* send the last or the only record */
r = send(fd, dp->d_name, 100, 0);
if (r < 0) {
perror("\nsend");
}
}
Another posibility to fix the problem is to close the conenction with the close(fd) syscall. It send all data in the buffer before closing the connection. It's a less clean, but more simple solution.
Your client prints the newline before lsbuf, hence everything since the previous newline is lost in your output buffer.
Four solutions:
use printf("%s\n", lsbuf); instead of ..."\n %s"...
use puts(lsbuf);, which has the same effect, but is slightly more appropriate
use fflush(stdout) after your client loop to flush the output buffer
use unbuffered output, see setvbuf() for details
Note that this problem doesn't seem to be networking-related (although I'd substitute MSG_MORE with 0), it's merely a problem with output buffering.
On a sidenote, I strongly suggest to send strlen(dp->d_name) + 1 bytes instead of 100 bytes. This way, you won't send more bytes than necessary, and on the other hand you won't truncate the output if your directory entries happen to be larger than 100 bytes.
Also, neither your client nor your server checks whether send()/recv() returns 0, which means that the connection has been closed by the remote end.

Sending while receiving in C

I've made a piece of code in what's on my server as multiple threads
The problem is that it doesn't send data while im receiving on the other socket.
so if i send something from to client 1 to client 2, client2 only receives if he sends something himself(jumps out of the recv function) .. how can i solve this ?
/* Thread*/
while (! stop_received) {
nr_bytes_recv = recv(s, buffer, BUFFSIZE, 0);
if(strncmp(buffer, "SEND", 4) == 0) {
char *message = "Text asads \n";
rv = send(users[0].s, message, strlen(message), 0);
rv = send(users[1].s, message, strlen(message), 0);
if (rv < 0) {
perror("Error sending");
exit(EXIT_FAILURE);
}
}else{
char *message = "Unknown command \n";
rv = send(s, message, strlen(message), 0);
if (rv < 0) {
perror("Error sending");
exit(EXIT_FAILURE);
}
}
}
To be a little more specific, there are a few types of I/O. What you're doing currently is called blocking i/o. In general that means that when you call send or recv the operation will "block" until it has completed.
In contrast to that there is what is known as non-blocking i/o. In this i/o model an operation will return immediately if it's unable to complete. Typically the select function is used with this i/o model.
You can see an example program here at the Select Tutorial. The full source code is at the bottom of the page.
As others have noted, your other option is to use threads.
Your code will block on the recv() call. Either write a multi-threaded application, or investigate the use of the select() function.
Put send and receive in separate threads.
I notice that you are using perror() (the POSIX error function), which leads me to believe you are using a POSIX operating system, which makes me suspect its GNU/Linux.
select() is portable, poll() is POSIX centric and epoll() is Linux centric. If using GNU/Linux, I strongly suggest avoiding select() and using:
poll() if you are polling only a few dozen file descriptors
epoll() if you need to scale to thousands of connections, and its available.
If your application need not be portable, and no requirement prohibits using extensions, use poll() or epoll(). Once you learn how select() works, you'll be very happy to get rid of it, especially for something that has to scale to serve many clients.
If portability is a requirement, see if either poll() or epoll() exist during your build configuration and use either in favor of select().
Note, epoll() did not appear until Linux 2.5(something), so its best to get used to using both.
You shoud separete the code in two threads, one transmitter and one receiver.
Somewthing like this:
/* 1st Thread*/
while (! stop_received) {
nr_bytes_recv = recv(s, buffer, BUFFSIZE, 0);
}
/* 2nd Thread*/
while (! stop_received) {
if(strncmp(buffer, "SEND", 4) == 0) {
char *message = "Text asads \n";
rv = send(users[0].s, message, strlen(message), 0);
rv = send(users[1].s, message, strlen(message), 0);
if (rv < 0) {
perror("Error sending");
exit(EXIT_FAILURE);
}
}else{
char *message = "Unknown command \n";
rv = send(s, message, strlen(message), 0);
if (rv < 0) {
perror("Error sending");
exit(EXIT_FAILURE);
}
}
}
The concurrency will bring some issues, like access to the buffer variable.
There are two ways of achieving the goal you want:
1.) implement the sending and receiving codes in different threads. but there will be some issues, like increasing no of clients might get you into troubles to handle the code. also there will be some some problem of concurrency (as mentioned by pcent).
you can go for no blocking sockets but i suggest not to do so, as i hope you dont want a cpu hog.
2.) The other way is to use of select() function which will let you monitor multiple sockets of different types at the same time. for more description of "select()" you can google it. :)

Resources