I have a chat application that has a separate thread to listen for incoming messages.
while (main thread not calling for receiver to quit) {
string message = tcpCon.tcpReceive(); // Relies on the recv() function
processIncomingMessage(message);
}
This way of working has one big problem. Most of the time, the loop will be blocking on recv() so the receiver thread won't quit. What would be a proper way to tackle this issue without forcing thread termination after a couple of seconds?
Close the socket with shutdown() to close it for all receivers.
This prints out 'recv returned 0' on my system, indicating that the receiver saw an orderly shutdown. Comment out shutdown() and watch it hang forever.
Longer term, OP should fix the design, either using select or including an explicit quit message in the protocol.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
/* Free on my system. YMMV */
int port = 7777;
int cd;
void *f(void *arg)
{
/* Hack: proper code would synchronize here */
sleep(1);
/* This works: */
shutdown(cd, SHUT_RDWR);
close(cd);
return 0;
}
int main(void)
{
/* Create a fake server which sends nothing */
int sd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sa = { 0 };
const int on = 1;
char buf;
pthread_t thread;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(port);
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
/* Other error reporting omitted for clarity */
if (bind(sd, (const struct sockaddr*)&sa, sizeof sa) < 0) {
perror("bind");
return EXIT_FAILURE;
}
/* Create a client */
listen(sd, 1);
cd = socket(AF_INET, SOCK_STREAM, 0);
connect(cd, (const struct sockaddr*)&sa, sizeof sa);
accept(sd, 0, 0);
/* Try to close socket on another thread */
pthread_create(&thread, 0, f, 0);
printf("recv returned %d\n", recv(cd, &buf, 1, 0));
pthread_join(thread, 0);
return 0;
}
You could use select() to wait for incoming data and avoid blocking in recv(). select() will also block, but you can have it time out after a set interval so that the while loop can continue and check for signals to quit from the main thread:
while (main thread not calling for receiver to quit) {
if (tcpCon.hasData(500)) { // Relies on select() to determine that data is
// available; times out after 500 milliseconds
string message = tcpCon.tcpReceive(); // Relies on the recv() function
processIncomingMessage(message);
}
}
If you close the socket in another thread, then recv() will exit.
calling close on the socket from any other thread will make the recv call fail instantly.
Related
I have set up a Winsock2 connection but I need to cover the case where internet is down. Here is my code;
#include <winsock2.h>
#include <windows.h>
#include <ctime>
int main()
{
WSADATA w;
if(WSAStartup(MAKEWORD(2,2),&w)) return 0;
sockaddr_in sad;
sad.sin_family=AF_INET;
sad.sin_addr.s_addr=inet_addr("200.20.186.76");
sad.sin_port=htons(123);
sockaddr saddr;
int saddr_l=sizeof(saddr);
int s=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(s==INVALID_SOCKET) return 0;
char msg[48]={8};
if(sendto(s,msg,sizeof(msg),0,(sockaddr*)&sad,sizeof(sad))==SOCKET_ERROR) return 0;
if(recvfrom(s,msg,48,0,&saddr,&saddr_l)==SOCKET_ERROR) return 0;
if(closesocket(s)==SOCKET_ERROR) return 0;
if(WSACleanup()) return 0;
return 0;
}
Here it waits for the call to return as it's documented. I have two questions.
Can I set a timeout like we can do when using select
How else can I prevent the waiting and make it return immediately? Documentation states that:
When issuing a blocking Winsock call such as sendto, Winsock may need to wait for a network event before the call can complete. Winsock performs an alertable wait in this situation, which can be interrupted by an asynchronous procedure call (APC) scheduled on the same thread.
How to do that?
If you want to issue a recvfrom() and have it return immediately, then decide on your own how long to wait (I'm assuming Windows since you included winsock2.h), you can make an asynchronous OVERLAPPED request, then wait for the completion at any time by waiting for the hEvent member of the OVERLAPPED struct to be signaled.
Here's an updated sample based off your original code.
you set the timeout by waiting as long as you need with WaitForSingleObject (below I wait for 10 seconds 6 times)
by passing an OVERLAPPED pointer, you are indicating that you will wait for the completion yourself. Note that the OVERLAPPED struct cannot go out of scope until the hEvent is signaled. (or freed, if the OVERLAPPED was dynamically allocated).
Letting the OVERLAPPED go out of scope before guaranteeing the IO completed is a common Winsock bug (I've been working on Winsock for over 10 years or so - I've seen many variations of this bug)
As commented below, if you don't know hEvent has been signaled, then after calling closesocket you must wait for hEvent to be signaled before continuing - closesocket does not guarantee all asynchronous IO request have completed before returning.
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <windows.h>
#include <ctime>
int main()
{
WSADATA w;
if (WSAStartup(MAKEWORD(2, 2), &w)) return 0;
sockaddr_in sad;
sad.sin_family = AF_INET;
sad.sin_addr.s_addr = inet_addr("200.20.186.76");
sad.sin_port = htons(123);
sockaddr saddr;
int saddr_l = sizeof(saddr);
int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == INVALID_SOCKET) return 0;
char msg[48] = { 8 };
if (sendto(s, msg, sizeof(msg), 0, (sockaddr*)&sad, sizeof(sad)) == SOCKET_ERROR) return 0;
OVERLAPPED ov{};
ov.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
if (ov.hEvent == nullptr) return 0;
WSABUF wsabuffer{};
wsabuffer.buf = msg;
wsabuffer.len = 48;
DWORD flags = 0;
if (WSARecvFrom(s, &wsabuffer, 1, nullptr, &flags, &saddr, &saddr_l, &ov, nullptr) == SOCKET_ERROR)
{
DWORD gle = WSAGetLastError();
if (gle != WSA_IO_PENDING) return 0;
}
for (DWORD recv_count = 0; recv_count < 6; ++recv_count)
{
DWORD wait = WaitForSingleObject(ov.hEvent, 10000);
if (wait == WAIT_FAILED) return 0;
if (wait == WAIT_OBJECT_0) break; // WSARecvFrom completed
if (wait == WAIT_TIMEOUT) continue; // WSARecvFrom is still pended waiting for data
}
// assuming WSARecvFrom completed - i.e. ov.hEvent was signaled
DWORD transferred;
if (WSAGetOverlappedResult(s, &ov, &transferred, FALSE, &flags))
{
// WSARecvFrom completed successfully - 'transferred' shows the # of bytes that were received
}
else
{
DWORD gle = WSAGetLastError();
gle;
// WSARecvFrom failed with the error code in 'gle'
}
if (closesocket(s) == SOCKET_ERROR) return 0;
// with real code, we must guarantee that hEvent is set after calling closesocket
// e.g. if we get here in an error path
// closesocket() won't guarantee all async IO has completed before returning
WaitForSingleObject(ov.hEvent, INFINITE);
if (WSACleanup()) return 0;
return 0;
}
I am trying to write client server application using udp protocol, but I have problem with connection ending.
I open two sockets (one is a "server" and the other is a "client"), and while the server receiving from the client with async, the client send him one simple message that printed to the console.
After some sleep (to be sure the server will call again to recv) the client and server socket getting closed.
At this point I expected the recv will return -1 and the async will end.
But what actualy happen is that the recv stuck forever*.
If just before closing the socket I sending an empty package (sendToMakeExit variable set to true in the code), the recv return with that empty package, and only after next call it return -1, although the socket was closed in the first calling.
const bool sendToMakeExit = false;
const int port = 2000;
const auto addr = "127.0.0.1";
int serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in target;
target.sin_family = AF_INET;
target.sin_port = htons(port);
inet_pton(AF_INET, addr, &target.sin_addr);
bind(serverSocket, (sockaddr *) &target, sizeof(target));
auto readAsync = std::async(std::launch::async, [&serverSocket] {
const int MAX_READ = 4096;
char readBuf[MAX_READ];
ssize_t actualRead;
do {
actualRead = recv(serverSocket, readBuf, MAX_READ, 0);
if (actualRead > 0) {
cout << readBuf << endl;
}
} while (actualRead != -1);
});
int clientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
connect(clientSocket, (sockaddr *) &target, sizeof(target));
this_thread::sleep_for(chrono::seconds(1));
send(clientSocket, "test", 5, 0);
this_thread::sleep_for(chrono::seconds(1));
close(clientSocket);
if (sendToMakeExit) {
sendto(serverSocket, nullptr, 0, 0, (sockaddr *) &target, sizeof(target));
}
close(serverSocket);
*If I run this code in debug and create new breakpoint when the recv is stuck surprisingly the recv return with -1.
How can I getting the recv will return -1 when I close the socket?
Closing a socket does not guarantee that any function call in another thread that is still using that socket immediately returns. If you have calls that wait for data to come in, like recv(), select(), poll(), you must send some data to the socket for these calls to return. You do that in your code, but you don't actually exit when a zero-length UDP packet is received: change the end of the while-loop to:
} while (actualRead > 0);
However, I would recommend having a flag variable that indicates whether the thread should continue running or not, like so:
volatile bool running = true;
auto readAsync = std::async(std::launch::async, [&serverSocket, &running] {
...
while (running) {
...recv()...
}
});
...
running = false;
sendto(serverSocket, ...);
readAsync.wait();
close(serverSocket);
Note that I added a line to wait for readAsync to finish before closing the socket, in order to prevent any accidents from happening: there is a small window where the socket is invalidated, but readAsync might still call recv() on it. If you have even more threads, it might also happen that you close the socket in this thread, another thread opens a new socket and gets the same filedescriptor number as the one you just closed, and then the readAsync thread would use the wrong socket.
I am trying to receive UDP messages in my main.cxx. I have created a UDP server method getUdp(char *buffer) to listen for incoming UDP messages in my while(true) infinite loop.
Here is the problem that I am facing. This UDP server is able to listen for one message at one time. When two or more UDP messages come at the same time, it is not queued into the buffer. I figured it is because the socket is everytime the method is called in the infinite loop, the getUdp() method opens a socket, gets the message and closes the socket, resulting in the server not being able to queue the messages.
How am I able to tweak this code to receive 2 or more UDP messages?
Appreciate any advice.
Thanks.
UdpServer.cpp
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <winsock.h>
#include <time.h>
#include "UdpServer.h"
#include "stdafx.h"
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 4096
void getUDP(char *buffer);
void UDPServer::MyUDP::getUDP(char *buffer)
{
WSADATA w; /* Used to open windows connection */
int client_length; /* Length of client struct */
int bytes_received; /* Bytes received from client */
SOCKET sd; /* Socket descriptor of server */
struct sockaddr_in server; /* Information about the server */
struct sockaddr_in client; /* Information about the client */
struct hostent *hp; /* Information about this computer */
char host_name[256]; /* Name of the server */
time_t current_time; /* Current time */
/* Open windows connection */
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
}
/* Open a datagram socket */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd == INVALID_SOCKET)
{
fprintf(stderr, "Could not create socket.\n");
WSACleanup();
}
/* Clear out server struct */
memset((void *)&server, '\0', sizeof(struct sockaddr_in));
/* Set family and port */
server.sin_family = AF_INET;
server.sin_port = htons(11000);
/* Set address automatically if desired */
/* Get host name of this computer */
gethostname(host_name, sizeof(host_name));
hp = gethostbyname(host_name);
/* Check for NULL pointer */
if (hp == NULL)
{
fprintf(stderr, "Could not get host name.\n");
closesocket(sd);
WSACleanup();
}
unsigned int a = 127;
unsigned int b = 0;
unsigned int c = 0;
unsigned int d = 1;
/* Assign the address */
server.sin_addr.S_un.S_un_b.s_b1 = a;
server.sin_addr.S_un.S_un_b.s_b2 = b;
server.sin_addr.S_un.S_un_b.s_b3 = c;
server.sin_addr.S_un.S_un_b.s_b4 = d;
/* Bind address to socket */
if (bind(sd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1)
{
fprintf(stderr, "Could not bind name to socket.\n");
closesocket(sd);
WSACleanup();
}
/* Print out server information */
printf("Server running on %u.%u.%u.%u\n", (unsigned char)server.sin_addr.S_un.S_un_b.s_b1,
(unsigned char)server.sin_addr.S_un.S_un_b.s_b2,
(unsigned char)server.sin_addr.S_un.S_un_b.s_b3,
(unsigned char)server.sin_addr.S_un.S_un_b.s_b4);
printf("Press CTRL + C to quit\n");
/* Loop and get data from clients */
client_length = (int)sizeof(struct sockaddr_in);
/* Receive bytes from client */
bytes_received = recvfrom(sd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &client_length);
if (bytes_received < 0)
{
fprintf(stderr, "Could not receive datagram.\n");
closesocket(sd);
WSACleanup();
}
current_time = time(NULL);
closesocket(sd);
WSACleanup();
}
main.cxx
int main(int argc, char** argv)
{
while(true)
{
//! wait for UDP message
UDPServer::MyUDP myudp;
myudp.getUDP(buffer);
if(buffer[0] != 0)
{
string udpMsg(buffer);
if(udpMsg == "ProcessThisMessage")
{
memset(&buffer[0], 0, sizeof(buffer));
cout << "UDP Message: " + udpMsg;
}
...
}
}
}
I figured it is because the socket is everytime the method is called
in the infinite loop, the getUdp() method opens a socket, gets the
message and closes the socket, resulting in the server not being able
to queue the messages.
Your intuition is correct. When you have a UDP socket bound to a port, the networking stack will buffer up (a finite number of) incoming UDP packets for you, so that (assuming you call recv() in a relatively timely manner), no incoming packets should get lost. But when you closesocket() the socket, that buffer is released, and of course during the times when no socket is bound to the UDP port and a UDP packet is received, the incoming UDP packet will simply be dropped (i.e. never buffered at all) because no sockets are bound to that port.
How am I able to tweak this code to receive 2 or more UDP messages?
Appreciate any advice.
Conceptually, at least, you'll need to split the getUdp() method into three separate parts: a Setup() part, that you call once when your program starts up, a Receive() part (containing just the recv() call) that you can call as many times as you like, to receive the next packet, and the finally a Cleanup() part that closes the socket and shuts down the TCP stack (which you would call only when your program is about to exit). That way the UDP socket remains valid and bound to the port the whole time your program is running, so that the OS will reliably buffer up the incoming UDP packets to give to your program via recv().
I am trying to design an echo server which has concurrently feature. It means, Server for each client, it create a parent and child processes. It is for a game server and each client play separately. I have come up with following code but I have no Idea why each time there is a message from client to server it starts to create a new process and start from for(;;){ // Run forever. As I said I think I must have one process for each client. I expect every process to remain in HandleTCPClient until client close its socket
Other issue is where can I initial my datas so each children process share it with itself.
#include "wrappers.h" // socket wrapper fns
#include <sys/wait.h> // for waitpid()
#define RCVBUFSIZE 32 // Size of receive buffer
void HandleTCPClient(int ClntSocket);
extern "C" void SigChldHandler( int Signum );
int i = 0;
int main(int argc, char *argv[])
{
int ServSock; // Socket descriptor for server
int ClntSock; // Socket descriptor for client
unsigned short EchoServPort; // Server port
sockaddr_in EchoServAddr; // Local address
sockaddr_in EchoClntAddr; // Client address
pid_t ProcessID; // Process ID from fork()
unsigned int ChildProcCount = 0; // Number of child processes
EchoServPort = SERV_TCP_PORT;; // First arg: local port
// Create socket for incoming connections
ServSock = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Construct local address structure
memset((char*)&EchoServAddr, 0, sizeof(EchoServAddr)); /* Zero out structure */
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 */
// Bind to the local address
Bind(ServSock, (sockaddr*)&EchoServAddr, sizeof(EchoServAddr));
// Mark the socket so it will listen for incoming connections
Listen(ServSock, 5);
signal(SIGCHLD, SigChldHandler); // for preventing zombies
for(;;){ // Run forever
// Set the size of the in-out parameter
socklen_t ClntLen = sizeof(EchoClntAddr);
// Wait for a client to connect
ClntSock = Accept(ServSock, (sockaddr*) &EchoClntAddr,&ClntLen);
//Startin point of new new player to server
// ClntSock is connected to a client!
printf("Handling client %s\n", inet_ntoa(EchoClntAddr.sin_addr));
// Fork child process and report any errors
if ((ProcessID = fork()) < 0){
perror("fork() failed");
exit(1);
}
if (ProcessID == 0){ // If this is the child process
close(ServSock); // Child closes (deallocates) its parent socket descriptor
HandleTCPClient(ClntSock);
exit(1); // Child process terminates
}
printf("With child process: %d\n", (int)ProcessID);
close(ClntSock); // Parent closes (deallocates) its child socket descriptor
ChildProcCount++; // Increment number of outstanding child processes
}
// NOT REACHED
}
void HandleTCPClient(int ClntSocket){
i++;
cout<<"Start of handling"<<endl;
cout<<"i="<<i<<endl;
char EchoBuffer[RCVBUFSIZE]; // Buffer for echo string
int RecvMsgSize; // Size of received message
// Receive message from client
if((RecvMsgSize = recv(ClntSocket, EchoBuffer, RCVBUFSIZE, 0)) < 0){
perror("recv() failed"); exit(1);
cout<<"Error"<<endl;
}
// Send received string and receive again until end of transmission
while(RecvMsgSize > 0){ // zero indicates end of transmission
// Echo message back to client
if(send(ClntSocket, EchoBuffer, RecvMsgSize, 0) != RecvMsgSize){
cout<<"Error"<<endl;
perror("send() failed"); exit(1);
}
// See if there is more data to receive
if((RecvMsgSize = recv(ClntSocket, EchoBuffer, RCVBUFSIZE, 0)) < 0){
cout<<"Error"<<endl;
perror("recv() failed"); exit(1);
}
}
close(ClntSocket); /* Close client socket */
cout<<"End of handling"<<endl;
}
extern "C" void SigChldHandler( int Signum ){
// Catch SIGCHLD signals so child processes don't become zombies.
pid_t pid;
int stat;
while((pid = waitpid(-1, &stat, WNOHANG)) > 0 );
return;
}
Output for three messages form client to server:
Handling client 127.0.0.1
With child process: 40830
Start of handling
i=1
Handling client 127.0.0.1
With child process: 40831
Start of handling
i=1
Handling client 127.0.0.1
With child process: 40832
Start of handling
i=1
Handling client 127.0.0.1
With child process: 40833
Start of handling
i=1
End of handling
End of handling
End of handling
End of handling
As you can see it creates three processes and when I close the program it will close socket for each process!!!
> Edit2 Client side is abstracted:
int main()
{
int Sockfd;
sockaddr_in ServAddr;
char ServHost[] = "localhost";
hostent *HostPtr;
int Port = SERV_TCP_PORT;
//int BuffSize = 0;
//Connection
// get the address of the host
HostPtr = Gethostbyname(ServHost);
if(HostPtr->h_addrtype != AF_INET){
perror("Unknown address type!");
exit(1);
}
memset((char *) &ServAddr, 0, sizeof(ServAddr));
ServAddr.sin_family = AF_INET;
ServAddr.sin_addr.s_addr = ((in_addr*)HostPtr->h_addr_list[0])->s_addr;
ServAddr.sin_port = htons(Port);
//Do some operation
while(!loop){
// open a TCP socket
Sockfd = Socket(AF_INET, SOCK_STREAM, 0);
// connect to the server
Connect(Sockfd, (sockaddr*)&ServAddr, sizeof(ServAddr));
//Prepare message to send server
// write a message to the server
write(Sockfd, data, sizeof(data));
int Len = read(Sockfd, data, 522);
//work on the message from server
}
close(Sockfd);
}
Your client is creating a new socket and connecting it before each write/read, not using the already connected one multiple times. The client should create a socket, connect it to the server and then perform as many write/reads as needed, without creating a new connection.
The server correctly treats each new connection as a new client, and forks to handle it.
Regarding sharing data between forked processes, you could use shared memory as described here.
The client calls socket and connect for every message it writes
while (...) {
socket(...);
connect(...); /* here the server forks a new child process */
write(...);
}
If you want to avoid that, you must move the connection before the loop
socket(...);
connect(...); /* here the server forks a new child process */
while (...) {
write(...);
}
I am trying to implement a server in C++/Linux that regularly takes user input from the terminal. Initially I had implemented two separate threads to handle this behavior. But I realized that I would need something like pthread_cancel to cancel the server thread in case the user wanted to shut down the server.
I then decided that it might be better to handle both actions in the same thread, so I dont have to worry about resource leakage. So what I have now is a 'select' call that selects over the stdin fd as well as my accepting fd. My code looks something like this...
fdset readfds;
FD_SET(acceptfd, &readfds);
FD_SET(stdinfd, &readfds);
while(1) {
select(n, &readfds, NULL, NULL, NULL);
....
}
For some reason I am no longer able to read input from stdin. This works fine when I remove either one of the two fds from my fd set, the other ome performs as expected. But when I leave them both in, while the acceptfd still accepts incoming connections, the stdinfd fails to respond to terminal input.
Does anyone know what I might be doing wrong here? Is this approach inherently flawed? Should I be focusing on keeping the two actions as separate threads and figuring out a way to exit cleanly instead?
Thanks for reading!!
As Ambroz commented, multiplexing stdin and some listened fd is possible.
But select is an old, nearly obsolete syscall, you should prefer using poll(2). If you insist on still using select(2) syscall, you should clear the readfds at first with FD_ZERO inside the loop. And the FD_SET macros should be inside the while loop, because select is permitted to modify the readfds.
The poll syscall is preferable to select because select impose a wired-in limit to the number of file descriptors the process can have (typically 1024, while the kernel is today able to deal with a bigger number of fds, eg 65536). In other words, select requires that every fd is < 1024 (which is false today). poll is able to deal with any set of any fd. The first argument to poll is an array (which you could calloc if you wanted to) whose size is the number of fds you want to multiplex. In your case, it is two (stdin and the second listened fd), so you can make it a local variable. Be sure to clear and initialize it before every call to poll.
You could debug with a debugger like gdb or just use strace
This epoll code works for me:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 4711
int main(void) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htons(INADDR_ANY);
bind(sockfd, (struct sockaddr*) &addr, sizeof (addr));
listen(sockfd, 10);
int epollfd = epoll_create1(0);
struct epoll_event event;
// add stdin
event.events = EPOLLIN|EPOLLPRI|EPOLLERR;
event.data.fd = STDIN_FILENO;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &event) != 0) {
perror("epoll_ctr add stdin failed.");
return 1;
}
// add socket
event.events = EPOLLIN|EPOLLPRI|EPOLLERR;
event.data.fd = sockfd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &event) != 0) {
perror("epoll_ctr add sockfd failed.");
return 1;
}
char *line = NULL;
size_t linelen = 0;
for (;;) {
int fds = epoll_wait(epollfd, &event, 1, -1);
if (fds < 0) {
perror("epoll_wait failed.");
return 2;
}
if (fds == 0) {
continue;
}
if (event.data.fd == STDIN_FILENO) {
// read input line
int read = getline(&line, &linelen, stdin);
if (read < 0) {
perror("could not getline");
return 3;
}
printf("Read: %.*s", read, line);
} else if (event.data.fd == sockfd) {
// accept client
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof (client_addr);
int clientfd = accept(sockfd, (struct sockaddr*) &client_addr, &addrlen);
if (clientfd == -1) {
perror("could not accept");
return 4;
}
send(clientfd, "Bye", 3, 0);
close(clientfd);
} else {
// cannot happen™
fprintf(stderr, "Bad fd: %d\n", event.data.fd);
return 5;
}
}
close(epollfd);
close(sockfd);
return 0;
}