I can't seem to get working 2 watchers per socket.. Code below doesn't acually works at all, but if i mix up these calls(for ex. call init/set/start for 1 watcher and then for other), i get only 1 watcher working.. Is there something I'm missing badly here...?
I don't think it has anything to do with loops and setup... I have 1 accept loop(default loop) and 1 loop for accepted connections. I tried both, running code below directly after accepting connection on accept loop and via ev_async_send(...) then executing this code from other io loop. Results were same.
Also setting both events on 1 watcher works fine too.
Thank you
ev_init (pSockWatcher->_wW, &CNetServer::send_cb);
ev_init (pSockWatcher->_wR, &CNetServer::recv_cb);
ev_io_set (pSockWatcher->_wW, pSockWatcher->_sd, EV_WRITE );
ev_io_set (pSockWatcher->_wR, pSockWatcher->_sd, EV_READ );
ev_io_start (loop, pSockWatcher->_wR);
ev_io_start (loop, pSockWatcher->_wW);
Well, here is an example with two I/O watchers on one socket fd, which seems to work fine for me. I am using the ev_io_init() function, however, not the ev_init() and ev_set().
#include <ev.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
static struct ev_loop *loop;
static ev_timer timeout_watcher;
static ev_io in_watcher, out_watcher;
static ev_idle idle_watcher;
static int sock_fd;
// socket input watcher
static void in_cb(EV_P_ ev_io *watcher, int revents) {
int r, t;
char buf[1024];
for (t = 0; (r = read(sock_fd, buf, sizeof(buf))) > 0;) {
t += r;
write(STDOUT_FILENO, buf, r); // copy input to stdout
if (buf[r-1] == '\n') break; // operate line-at-a-time
}
fprintf(stderr, "in: count = %d\n", t);
if (r == 0) {
fputs("in: connection closed\n", stderr);
ev_io_stop(loop, &in_watcher); // stop the socket watcher
ev_break(loop, EVBREAK_ALL); // exit the loop
} else if (r < 0) {
perror("read");
}
}
// socket output watcher
static void out_cb(EV_P_ ev_io *watcher, int revents) {
int r, t, lim;
char buf[1024];
ev_io_stop(loop, &out_watcher);
for (t = 0; t < sizeof(buf); t++) {
buf[t] = 'a' + (rand() % 26);
}
for (t = 0, lim = rand() % 10000 + 1000;
(r = write(sock_fd, buf, (lim - t > sizeof(buf)) ? sizeof(buf) : lim - t)) > 0;) {
t += r;
if (t >= lim) break;
}
if (r < 0) {
perror("write");
}
fprintf(stderr, "out: finished sending, count = %d\n", t);
}
static void timeout_cb(EV_P_ ev_timer *watcher, int revents) {
fprintf(stderr, "timeout: now = %f\n", ev_now(loop));
// send a bunch of stuff on the socket when able
ev_io_start (loop, &out_watcher);
}
static void idle_cb(EV_P_ ev_idle *watcher, int revents) {
static long idle_count = 0;
fprintf(stderr, "idle: count = %ld\n", ++idle_count);
sleep(1); // simulate doing stuff
}
int main() {
extern int errno;
int master_fd;
int sock_opt = 1;
int conn_port = 7000;
struct sockaddr_in addr;
socklen_t addrlen;
// **** the following is needed to set up a socket to receive data ****
master_fd = socket(AF_INET, SOCK_STREAM, 0);
if (master_fd == -1) {
perror("socket");
return errno;
}
if (setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &sock_opt, sizeof(sock_opt)) == -1) {
perror("setsockopt");
return errno;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(conn_port);
addrlen = sizeof(addr);
if (bind(master_fd, (struct sockaddr *) &addr, addrlen) != 0) {
perror("bind");
return errno;
}
if (listen(master_fd, 3) != 0) {
perror("listen");
return errno;
}
fprintf(stderr, "awaiting a connection on port %d\n", conn_port);
sock_fd = accept(master_fd, (struct sockaddr *) &addr, &addrlen);
if (sock_fd == -1) {
perror("accept");
return errno;
}
fputs("in: connection established\n", stderr);
// **** end of socket setup code ****
// define a loop
loop = ev_default_loop(0);
// define a repeating timer
ev_timer_init (&timeout_watcher, timeout_cb, 5.0, 5.0);
ev_timer_start (loop, &timeout_watcher);
// define an idle process
ev_idle_init(&idle_watcher, idle_cb);
ev_idle_start (loop, &idle_watcher);
// define the socket data receiver
ev_io_init(&in_watcher, in_cb, sock_fd, EV_READ);
ev_io_start (loop, &in_watcher);
// define the socket data write complete watcher
ev_io_init(&out_watcher, out_cb, sock_fd, EV_WRITE);
// run the loop
ev_run(loop, 0);
// clean up
close(sock_fd);
close(master_fd);
return 0;
}
Related
New to socket programming, trying to implement a TCP server, but accept() returns -1 and errno = 9 (bad file descriptor). The problem arose after I introduced the accept() function in the freertos task. I really don’t understand what the problem is here, because before this my action everything worked, but I need to use the task.
#include "TCP.hpp"
#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <clocale>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "freertos/queue.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#include "ping/ping_sock.h"
#include "errno.h"
static const char *TAG = "TCP";
QueueHandle_t TCP::xQueue1 = NULL;
ip_addr_t TCP::target_addr;
int TCP::ip_protocol;
int TCP::listen_sock;
sockaddr_in TCP::servaddr;
sockaddr_in TCP::cliaddr;
char TCP::addr_str[128];
char TCP::buf[128];
int TCP::sock;
TCP::Clbk_t TCP::clbk_tcp_recv = nullptr;
sockaddr_storage TCP::source_addr;
typedef struct
{
int len;
void * dataPtr;
}message;
void TCP::tcp_set_Clbk(Clbk_t clbk)
{
clbk_tcp_recv = clbk;
}
void TCP::tcp_create_server(sa_family_t serv_family, in_addr_t serv_addr, in_port_t serv_port)
{
int opt = 1;
struct sockaddr_in6 *servaddrPtr;
if (serv_family == AF_INET){
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_len = 24;
servaddr.sin_family = serv_family;
servaddr.sin_addr.s_addr = serv_addr;
servaddr.sin_port = htons(serv_port);
ip_protocol = IPPROTO_IP;
} else if (serv_family == AF_INET6){
servaddrPtr = (struct sockaddr_in6 *)&servaddr;
servaddrPtr->sin6_len = 24;
servaddrPtr->sin6_family = serv_family;
servaddrPtr->sin6_port = htons(serv_port);
ip_protocol = IPPROTO_IPV6;
}
ESP_LOGI(TAG, "Create socket...\n");
if ((listen_sock = socket(serv_family, SOCK_STREAM, ip_protocol)) < 0) {
ESP_LOGE(TAG, "socket not created\n");
}
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
ESP_LOGI(TAG, "Socket created");
int err = bind(listen_sock, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to bind errno %d", errno);
ESP_LOGE(TAG, "IPPROTO: %d", serv_family);
goto CLEAN_UP;
}
ESP_LOGI(TAG, "Socket bound, port %d", serv_port);
err = listen(listen_sock, 1);
if (err != 0) {
ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
goto CLEAN_UP;
}
ESP_LOGI(TAG, "Soccket listening . . .");
xTaskCreate(tcp_listening_task, "tcp_listening_task", 4096, nullptr, 5, nullptr);
CLEAN_UP:
close(listen_sock);
}
void TCP::tcp_listening_task(void *arg)
{
int keepAlive = 1;
socklen_t addr_len = sizeof(source_addr);
ESP_LOGI(TAG, "Socket %d ",listen_sock);
for (;;) {
sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
ESP_LOGI(TAG, "Socket %d ",sock);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
}
if (sock > 0) {
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int));
if (source_addr.ss_family == PF_INET) {
inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1);
}
else if (source_addr.ss_family == PF_INET6) {
inet6_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1);
}
ESP_LOGI(TAG, "Socket %d accepted ip address: %s",sock, addr_str);
xTaskCreate(tcp_task_recv, "tcp_task_recv", 4096, nullptr, 5, nullptr);
}
}
}
void TCP::tcp_task_recv(void *arg)
{
int n;
int number_receiving = 0;
struct timeval tv;
tv.tv_sec = 1;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval));
ESP_LOGI(TAG,"server waiting message");
for (;;) {
n = recv(sock, (char *)buf, sizeof(buf), 0);
if (n < 0) {
ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);
number_receiving++;
if (number_receiving == 10) {
number_receiving = 0;
}
}
else if (n == 0) {
ESP_LOGW(TAG, "Connection closed");
number_receiving = 0;
}
else {
if (clbk_tcp_recv != nullptr) clbk_tcp_recv(buf, n, (struct sockaddr *)&source_addr);
number_receiving = 0;
}
}
}
void TCP::tcp_sendd(void *data, uint32_t length)
{
static message msg;
xQueue1 = xQueueCreate(10, sizeof(message));
xTaskCreate(tcp_task_send, "udp_task_send", 4096, nullptr, 5, nullptr);
if(sock < 0){
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
return;
}
if(xQueue1 == NULL){
ESP_LOGE(TAG, "queue is null");
return;
}
msg.dataPtr = data;
msg.len = length;
xQueueSend(xQueue1, (void *)&msg, portMAX_DELAY);
}
void TCP::tcp_task_send(void *arg)
{
message pxRxedMessage;
for(;;)
{
xQueueReceive(xQueue1, (void *)&pxRxedMessage, portMAX_DELAY);
int err = send(sock, pxRxedMessage.dataPtr, pxRxedMessage.len, 0);
if (err < 0){
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
}
}
}
I tried to look for information on this issue, but since. I'm also new to c++ programming, nothing worked out
You should be passing the listen_sock as the arg parameter to tcp_listening_task(), rather than using a static class member, eg:
int listen_sock = socket(...);
...
xTaskCreate(tcp_listening_task, "tcp_listening_task", 4096, reinterpret_cast<void*>(listen_sock), 5, nullptr);
...
void TCP::tcp_listening_task(void *arg)
{
int listen_sock = reinterpret_cast<int>(arg);
...
close(listen_sock);
}
And especially the same with sock and tcp_task_recv() too, since your server is designed to handle multiple clients being connected simultaneously, which you can't handle with a single static sock variable:
int sock = accept(...);
...
xTaskCreate(tcp_task_recv, "tcp_task_recv", 4096, reinterpret_cast<void*>(sock), 5, nullptr);
...
void TCP::tcp_task_recv(void *arg)
{
int sock = reinterpret_cast<int>(arg);
...
close(sock);
}
#include <stdio.h>
#include <time.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "WS2_32.lib")
#define IP_ADDRESS "127.0.0.1"
#define PORT 20000
#define BUF_SIZE 64
#undef FD_SETSIZE
#define FD_SETSIZE 10000
void shuffle_buffer(char* buf, size_t size);
SOCKET create_socket();
void send_data(SOCKET sock);
int main()
{
WSADATA ws;
if (WSAStartup(MAKEWORD(2, 2), &ws) != 0)
{
printf("Init Windows Socket Failed::%d\n", GetLastError());
return -1;
}
const int CLIENT_SIZE = 1;
SOCKET socks[CLIENT_SIZE];
struct timeval tv = { 0, 10 };
fd_set fd_read, fd_write;
FD_ZERO(&fd_read);
FD_ZERO(&fd_write);
for (int i = 0; i < CLIENT_SIZE; i++) {
SOCKET sock = create_socket();
socks[i] = sock;
FD_SET(sock, &fd_write);
FD_SET(sock, &fd_read);
}
Sleep(1000);
int number_to_recv = CLIENT_SIZE;
while (number_to_recv > 0) {
int ret = select(CLIENT_SIZE, &fd_read, &fd_write, NULL, &tv);
for (int i = 0; i < CLIENT_SIZE; i++) {
if (FD_ISSET(socks[i], &fd_read)) {
char buf[BUF_SIZE];
int n = recv(socks[i], buf, BUF_SIZE, 0);
buf[n] = 0;
printf("%s\n", buf);
number_to_recv--;
}
if (FD_ISSET(socks[i], &fd_write)) {
send_data(socks[i]);
FD_CLR(socks[i], &fd_write);
//Sleep(1);
}
}
//printf("ret and number : %d, %d\n", ret, number_to_recv);
}
for (int i = 0; i < CLIENT_SIZE; i++) {
closesocket(socks[i]);
}
WSACleanup();
}
SOCKET create_socket()
{
SOCKET cli_sock;
struct sockaddr_in addr;
if ((cli_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
printf("Create Socket Failed::%d\n", GetLastError());
return -1;
}
//inet_pton
memset(addr.sin_zero, 0x00, 8);
addr.sin_family = AF_INET;
inet_pton(AF_INET, IP_ADDRESS, (void*)(&addr.sin_addr.s_addr));
addr.sin_port = htons(PORT);
if (connect(cli_sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
printf("Connect Error::%d\n", GetLastError());
return -1;
}
return cli_sock;
}
void send_data(SOCKET sock)
{
const int SEND_SIZE = BUF_SIZE / 2;
char buf[SEND_SIZE] = { 0 };
memset(buf, 'a', SEND_SIZE);
shuffle_buffer(buf, SEND_SIZE);
if (send(sock, buf, SEND_SIZE, 0) == SOCKET_ERROR)
{
printf("Send Info Error::%d\n", GetLastError());
}
}
void shuffle_buffer(char* buf, size_t size)
{
for (int i = 0; i < size; i++) {
buf[i] += int(rand() % 26);
}
}
Code above is a socket client using select model run on Win10, the problem is after I send data, but I can not receive data(I am sure that server has sent back data), this code below doesn`t run, so what is the problem? Thanks
The first parameter in select is maxfdp, and I know the difference between Win and Unix, so on Windows, this parameter seems not necessary, and I can write data,
but can not receive it.
if (FD_ISSET(socks[i], &fd_read)) {
char buf[BUF_SIZE];
int n = recv(socks[i], buf, BUF_SIZE, 0);
buf[n] = 0;
printf("%s\n", buf);
number_to_recv--;
}
select removes the sockets from the fd_set if they are not readable/writable. You need to add them back in before the next time you call select.
The reason your code can write data is because sockets start out being writable, so they will still be set in fd_write and your code will write data. They don't start out being readable, if no data has been received yet, so they'll be removed from the fd_read set and then your code stops checking whether they are readable.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am writing a network client-server program:
Server side:
#include "stdafx.h"
#include <winsock.h>
#include <stdio.h>
#include<stdlib.h>
#define PROTOPORT 5193
#define QLEN 6
#define BUFFERSIZE 512
void ErrorHandler(char *errorMessage)
{
printf(errorMessage);
}
void ClearWinSock()
{
#if defined WIN32
WSACleanup();
#endif
}
int main(int argc, char *argv[])
{
int port;
if (argc > 1)
port = atoi(argv[1]);
else
port = PROTOPORT;
if (port < 0) {
printf("Bad port number %s \n", argv[1]);
return 0;
}
#if defined WIN32
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
ErrorHandler("Error at WSAStartup()\n");
return 0;
}
#endif
//creazione della socket
int MySocket;
MySocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (MySocket < 0) {
ErrorHandler("socket creation failed.\n");
ClearWinSock();
return 0;
}
//ASSEGNAZIONE DI UN INDIRIZZO ALLA SOCKET
struct sockaddr_in sad;
memset(&sad, 0, sizeof(sad)); // ensures that extra bytes contain 0
sad.sin_family = AF_INET;
sad.sin_addr.s_addr = inet_addr("127.0.0.1");
sad.sin_port = htons(port); /* converts values between the host and
network byte order. Specifically, htons() converts 16-bit quantities
from host byte order to network byte order. */
if (bind(MySocket, (struct sockaddr*) &sad, sizeof(sad)) < 0) {
ErrorHandler("bind() failed.\n");
closesocket(MySocket);
ClearWinSock();
return 0;
}
// SETTAGGIO DELLA SOCKET ALL'ASCOLTO
if (listen(MySocket, QLEN) < 0) {
ErrorHandler("listen() failed.\n");
closesocket(MySocket);
ClearWinSock();
return 0;
}
// ACCETTARE UNA NUOVA CONNESSIONE
struct sockaddr_in cad; // structure for the client address
int clientSocket; // socket descriptor for the client
int clientLen; // the size of the client address
printf("Waiting for a client to connect...");
while (1) {
clientLen = sizeof(cad); // set the size of the client address
if ((clientSocket = accept(MySocket, (struct sockaddr *)&cad,
&clientLen)) < 0) {
ErrorHandler("accept() failed.\n");
//RICEZIONE DATI TEST
int bytesRcvd;
int totalBytesRcvd = 0;
int Csocket;
Csocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
char buf[BUFFERSIZE]; // buffer for data from the server
printf("Received: "); // Setup to print the echoed string
if ((bytesRcvd = recv(Csocket, buf, BUFFERSIZE - 1, 0)) <= 0) {
ErrorHandler("recv() failed or connection closed prematurely");
closesocket(Csocket);
ClearWinSock();
return 0;
}
totalBytesRcvd += bytesRcvd; // Keep tally of total bytes
buf[bytesRcvd] = '\0'; // Add \0 so printf knows where to stop
printf("%s", buf); // Print the echo buffer
// CHIUSURA DELLA CONNESSIONE
closesocket(MySocket);
ClearWinSock();
return 0;
}
printf("Handling client %s\n", inet_ntoa(cad.sin_addr));
}
}
and client side:
#include "stdafx.h"
#include <winsock.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFERSIZE 512
#define PROTOPORT 5193
void ErrorHandler(char *errorMessage) {
printf(errorMessage);
}
void ClearWinSock() {
WSACleanup();
}
int main(void) {
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("error at WSASturtup\n");
return 0;
}
// CREAZIONE DELLA SOCKET
int Csocket;
Csocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Csocket < 0) {
ErrorHandler("socket creation failed.\n");
closesocket(Csocket);
ClearWinSock();
return 0;
}
// COSTRUZIONE DELL’INDIRIZZO DEL SERVER
struct sockaddr_in sad;
memset(&sad, 0, sizeof(sad));
sad.sin_family = AF_INET;
sad.sin_addr.s_addr = inet_addr("127.0.0.1"); // IP del server
sad.sin_port = htons(5193); // Server port
// CONNESSIONE AL SERVER
if (connect(Csocket, (struct sockaddr *)&sad, sizeof(sad)) < 0)
{
ErrorHandler("Failed to connect.\n");
closesocket(Csocket);
ClearWinSock();
return 0;
}
char* inputString = "prova"; // Stringa da inviare
int stringLen = strlen(inputString); // Determina la lunghezza
// INVIARE DATI AL SERVER
if (send(Csocket, inputString, stringLen, 0) != stringLen) {
ErrorHandler("send() sent a different number of bytes than expected");
closesocket(Csocket);
ClearWinSock();
return 0;
}
// RICEVERE DATI DAL SERVER
int bytesRcvd;
int totalBytesRcvd = 0;
char buf[BUFFERSIZE]; // buffer for data from the server
printf("Received: "); // Setup to print the echoed string
while (totalBytesRcvd < stringLen) {
if ((bytesRcvd = recv(Csocket, buf, BUFFERSIZE - 1, 0)) <= 0) {
ErrorHandler("recv() failed or connection closed prematurely");
closesocket(Csocket);
ClearWinSock();
return 0;
}
totalBytesRcvd += bytesRcvd; // Keep tally of total bytes
buf[bytesRcvd] = '\0'; // Add \0 so printf knows where to stop
printf("%s", buf); // Print the echo buffer
}
// CHIUSURA DELLA CONNESSIONE
closesocket(Csocket);
ClearWinSock();
printf("\n"); // Print a final linefeed
system("pause");
return(0);
}
I have problems in output the string i've passed from client to server: "prova".
Can someone tell me where is error? The code doesn't give me any error.
You are receiving data only when accept failed:
if ((clientSocket = accept(MySocket, (struct sockaddr *)&cad,
&clientLen)) < 0) {
ErrorHandler("accept() failed.\n");
int bytesRcvd;
int totalBytesRcvd = 0;
...
What you need to do is just add a else case:
if ((clientSocket = accept(MySocket, (struct sockaddr *)&cad,
&clientLen)) < 0) {
ErrorHandler("accept() failed.\n");
} else {
int bytesRcvd;
int totalBytesRcvd = 0;
... // receive code here
// clientSocket is the socket to communicate with client
// call recv on it, not the other socket you created in the loop
}
The accept() call returns 'clientSocket', which you promptly ignore and dream up some new 'Csocket' to receive on.
Don't do that.
if ((bytesRcvd = recv(clientSocket, buf, BUFFERSIZE - 1, 0)) <= 0) {
This is the new Server side:
#include "stdafx.h"
#include <winsock.h>
#include <stdio.h>
#include<stdlib.h>
#define PROTOPORT 5193
#define QLEN 6
#define BUFFERSIZE 512
void ErrorHandler(char *errorMessage)
{
printf(errorMessage);
}
void ClearWinSock()
{
#if defined WIN32
WSACleanup();
#endif
}
int main(int argc, char *argv[])
{
int port;
if (argc > 1)
port = atoi(argv[1]);
else
port = PROTOPORT;
if (port < 0) {
printf("Bad port number %s \n", argv[1]);
return 0;
}
#if defined WIN32
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
ErrorHandler("Error at WSAStartup()\n");
return 0;
}
#endif
//creazione della socket
int MySocket;
MySocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (MySocket < 0) {
ErrorHandler("socket creation failed.\n");
ClearWinSock();
return 0;
}
//ASSEGNAZIONE DI UN INDIRIZZO ALLA SOCKET
struct sockaddr_in sad;
memset(&sad, 0, sizeof(sad)); // ensures that extra bytes contain 0
sad.sin_family = AF_INET;
sad.sin_addr.s_addr = inet_addr("127.0.0.1");
sad.sin_port = htons(port); /* converts values between the host and
network byte order. Specifically, htons() converts 16-bit quantities
from host byte order to network byte order. */
if (bind(MySocket, (struct sockaddr*) &sad, sizeof(sad)) < 0) {
ErrorHandler("bind() failed.\n");
closesocket(MySocket);
ClearWinSock();
return 0;
}
// SETTAGGIO DELLA SOCKET ALL'ASCOLTO
if (listen(MySocket, QLEN) < 0) {
ErrorHandler("listen() failed.\n");
closesocket(MySocket);
ClearWinSock();
return 0;
}
// ACCETTARE UNA NUOVA CONNESSIONE
struct sockaddr_in cad; // structure for the client address
int clientSocket; // socket descriptor for the client
int clientLen; // the size of the client address
printf("Waiting for a client to connect...");
while (1) {
clientLen = sizeof(cad); // set the size of the client address
if ((clientSocket = accept(MySocket, (struct sockaddr *)&cad,
&clientLen)) < 0) {
ErrorHandler("accept() failed.\n");
}else{
//RICEZIONE DATI TEST
int bytesRcvd;
int totalBytesRcvd = 0;
char buf[BUFFERSIZE]; // buffer for data from the server
printf("Received: "); // Setup to print the echoed string
if ((bytesRcvd = recv(clientSocket, buf, BUFFERSIZE - 1, 0)) <= 0) {
ErrorHandler("recv() failed or connection closed prematurely");
closesocket(clientSocket);
ClearWinSock();
return 0;
totalBytesRcvd += bytesRcvd; // Keep tally of total bytes
buf[bytesRcvd] = '\0'; // Add \0 so printf knows where to stop
printf("%s", buf); // Print the echo buffer
} Sleep(10);
// CHIUSURA DELLA CONNESSIONE
closesocket(MySocket);
ClearWinSock();
return 0;
}
printf("Handling client %s\n", inet_ntoa(cad.sin_addr));
system("pause");
}
}
In a project I am currently doing in group, we have to build a card game from scratch that uses sockets (Linux). We also have to build a chat room that every player can use.
So far so good. The chat is implemented using three separate threads, one that receives incoming connections (up to 50) and stores them in a client list, one that constantly waits for messages from all connected clients, and one that is created each time a client sends a message, sending that message to all clients in the client list. All of this works, except when a single client disconnects.
I managed to keep the server alive (with a sig handler for SIGPIPE) when a client disconnects, but now, when a client disconnects, I keep getting the error Bad file descriptor. But that's not the only problem, since the server keeps receiving empty messages and sends them to the remaining clients, effectively flooding the whole chat in a matter of milliseconds with empty messages.
I believe that if I can fix the problem on the server side, there won't be any problems on the client side.
So my question is: What is the right way (or any way) to manage a Bad file descriptor in my case. I've already tried closing the socket FD and setting the value to -1 in the client list, but that created even more problems and didn't fix the initial ones.
Here is the code, if necessary. The most important function (for the chat) are reception_thread, chat_thread, receive_string, send_string and connect_to_chat on the client side.
Here is the client:
//includes
const int PORT = 2477;
const int CHAT_PORT = 2478;
#define DEBUG
//error()
// Sets up the connection to the server.
//connect_to_server()
int connect_to_chat(char * hostname)
{
#ifdef DEBUG
printf("[DEBUG] Initiating connection to chat server.\n");
#endif
struct sockaddr_in serv_addr;
struct hostent *server;
// Get a socket.
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("Error opening socket for server.");
// Get the address of the server.
server = gethostbyname(hostname);
if (server == NULL) {
fprintf(stderr, "ERROR, no such host\n");
exit(0);
}
// Zero out memory for server info.
memset(&serv_addr, 0, sizeof (serv_addr));
// Set up the server info.
serv_addr.sin_family = AF_INET;
memmove(server->h_addr, &serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(CHAT_PORT);
// Make the connection.
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("Error connecting to chat server");
#ifdef DEBUG
printf("[DEBUG] Connected to server.\n");
#endif
return sockfd;
}
//-------------------------------- Messages ------------------------------------
// Bunch of send/recv functions that are not important to chat
int send_string(int sockfd, std::string myString)
{
#ifdef DEBUG
printf("[DEBUG] Sending string: %s.\n", myString.c_str());
#endif
//send size
uint32_t stringLen = myString.size();
uint32_t sendLen = htonl(stringLen);
int n = send(sockfd, &sendLen, sizeof (uint32_t), 0);
if (n < 0) {
error("Error sending message (string size). Removing client from list.");
return -1;
}
//send string
n = send(sockfd, myString.c_str(), stringLen, 0);
if (n < 0) {
error("Error sending message (string). Removing client from list.");
return -1;
}
return 0;
}
std::string receive_string(int sockfd)
{
//get string length
uint32_t stringLen;
int n = recv(sockfd, &stringLen, sizeof (uint32_t), 0);
if (n < 0) {
perror("Error receiving message(string size).");
}
stringLen = ntohl(stringLen);
std::vector<uint8_t> buffer;
buffer.resize(stringLen, 0x00);
//get string
n = recv(sockfd, &(buffer[0]), stringLen, 0);
if (n < 0) {
perror("Error receiving message(string).");
}
std::string returnString;
returnString.assign(reinterpret_cast<const char*> (&(buffer[0])), buffer.size()); //might be a bad idea, but it works
#ifdef DEBUG
printf("[DEBUG] Received message: %s\n", returnString.c_str());
#endif
return returnString;
}
//----------------------------- Printing functions------------------------------
void print_menu_guest()
{
// some visual function
}
void print_menu_user()
{
// some visual function
}
void print_info()
{
std::cout << " No information available on the game yet." << std::endl;
}
//---------------------------- Account functions -------------------------------
// Not necessary for chat functions
//--------------------------- Chat thread functions ----------------------------
void reception_thread(int sockfd)
{
#ifdef DEBUG
printf("[DEBUG] Reception thread started.\n");
#endif
std::string stringToPrint;
while (1) {
stringToPrint = receive_string(sockfd);
std::cout << stringToPrint << std::endl;
}
}
void chat_thread(int sockfd, char* host)
{
#ifdef DEBUG
printf("[DEBUG] Chat thread started.\n");
#endif
std::string myString, myUsername, blank;
std::cout << "Enter your username (NO SPACES): ";
std::cin >> myUsername;
myUsername += ": ";
int chat_sockfd = connect_to_chat(host);
std::thread reception_thr(reception_thread, chat_sockfd);
reception_thr.detach();
while (1) {
getline(std::cin, myString);
if (!myString.empty()) {
if (myString != "/quit") {
send_string(chat_sockfd, (myUsername + myString));
}
else {
printf("On peut pas encore quitter :( ");
}
}
}
}
//---------------------- Menu management functions -----------------------------
// Main menu function
//---------------------------- Main function -----------------------------------
int main(int argc, char** argv)
{
/* Make sure host and port are specified. */
if (true) {
char* hostname = "localhost";
/* Connect to the server. */
int sockfd = connect_to_server(hostname);
#ifdef DEBUG
printf("[DEBUG] Client ID: Not yet implemented. ");
#endif
login_prompt(sockfd);
user_menu_loop(sockfd);
}
return 0;
}
And here is the server: Its most important functions (for the chat) are setup_user_fetcher, message_receiver, send_string_to_all, receive_string, send_string, get_chat_user, setup_chat_listener.
// Bunch of includes
const int PORT = 2477;
const int CHAT_PORT = 2478;
const int BACKLOG = 10;
const int MAX_CLIENTS = 20;
int clients_list[50] = {-1};
#define DEBUG
void error(const char *msg)
{
perror(msg);
}
/* Catch Signal Handler functio */
void signal_callback_handler(int signum){
printf("Caught signal SIGPIPE %d\n",signum);
}
//-------------------------- Server set-up functions ---------------------------
// Not necessary for chat
//--------------------------- Chat server functions ---------------------------
int setup_chat_listener()
{
int sockfd;
struct sockaddr_in serv_addr;
// Get a socket to listen on
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening listener socket.");
// Zero out the memory for the server information
memset(&serv_addr, 0, sizeof (serv_addr));
// set up the server info
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(CHAT_PORT);
// Bind the server info to the listener socket.
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("Error binding listener socket.");
#ifdef DEBUG
printf("[DEBUG] Chat listener set.\n");
#endif
// Return the socket number.
return sockfd;
}
int get_chat_user(int sockfd)
{
#ifdef DEBUG
printf("[DEBUG] Getting chat user.\n");
#endif
struct sockaddr_in their_addr;
socklen_t sin_size;
if (listen(sockfd, BACKLOG) < 0) {
perror("Error while listening.");
exit(EXIT_FAILURE);
}
sin_size = sizeof (struct sockaddr_in);
// Mise a zero de la memoire pour le client.
memset(&their_addr, 0, sin_size);
int new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size);
if (new_fd < 0)
error("Error while accepting.");
printf("Chat server: Connection received from: %s\n",
inet_ntoa(their_addr.sin_addr));
return new_fd;
}
int send_string(int sockfd, std::string myString)
{
#ifdef DEBUG
printf("[DEBUG] Sending string to client %d.\n", sockfd);
#endif
uint32_t stringLen = myString.size();
uint32_t sendLen = htonl(stringLen);
int n = send(sockfd, &sendLen, sizeof (uint32_t), 0);
if (n < 0) {
error("Error sending message (string size). Removing client from list.");
return -1;
}
//send string
n = send(sockfd, myString.c_str(), stringLen, 0);
if (n < 0) {
error("Error sending message (string). Removing client from list.");
return -1;
}
return 0;
}
std::string receive_string(int sockfd)
{
#ifdef DEBUG
printf("[DEBUG] Receiving string.\n");
printf("Current chat user sockfd: %d\n", sockfd);
#endif
uint32_t stringLen;
int n = recv(sockfd, &stringLen, sizeof (uint32_t), 0);
#ifdef DEBUG
printf("[DEBUG] String size received: %d.\n", stringLen);
#endif
if (n < 0) {
perror("Error receiving message(string size).");
}
stringLen = ntohl(stringLen);
std::vector<uint8_t> buffer;
buffer.resize(stringLen, 0x00);
//get string
n = recv(sockfd, &(buffer[0]), stringLen, 0);
if (n < 0) {
perror("Error receiving message(string).");
close(sockfd);
}
std::string returnString;
returnString.assign(reinterpret_cast<const char*> (&(buffer[0])), buffer.size()); //might be a bad idea, but it works
#ifdef DEBUG
printf("[DEBUG] Received message: %s\n", returnString.c_str());
#endif
return returnString;
}
void send_string_to_all(std::string myString)
{
#ifdef DEBUG
printf("[DEBUG] Sending string to all clients.\n");
#endif
int n;
for (int i = 0; i < 50; ++i) {
if (clients_list[i] != -1) {
n = send_string(clients_list[i], myString);
if (n < 0) {
close(clients_list[i]);
clients_list[i] = -1;
}
}
}
}
void message_receiver(int sockfd)
{
#ifdef DEBUG
printf("[DEBUG] Setting up message receiver.\n");
printf("Current chat user sockfd: %d", sockfd);
#endif
std::string message;
int n;
while (1) {
message = receive_string(sockfd);
std::thread t1(send_string_to_all, message);
t1.detach();
}
}
//------------------------------------------------------------------------------
// Bunch of send/recv functions, not necessary to chat
//----------------------------Account Functions---------------------------------
// Not necessary to chat
//------------------------------------------------------------------------------
// Main menu function
void setup_user_fetcher(int lis_chat_sockfd)
{
#ifdef DEBUG
printf("[DEBUG] Gotta catch'em all.\n");
#endif
while (1) {
int chat_user_sockfd = get_chat_user(lis_chat_sockfd);
for (int i = 0; i < 50; ++i)
if (clients_list[i] == -1) {
clients_list[i] = chat_user_sockfd;
break;
}
std::thread message_receiver_thread(message_receiver, chat_user_sockfd);
message_receiver_thread.detach();
}
}
int main(int argc, char** argv)
{
signal(SIGPIPE, signal_callback_handler);
int lis_sockfd = setup_listener();
int lis_chat_sockfd = setup_chat_listener();
std::thread chat_thread(setup_user_fetcher, lis_chat_sockfd);
chat_thread.detach();
while (1) {
int user_sockfd = get_user(lis_sockfd);
int* user_sockfd_ptr = (int*) malloc(sizeof (int));
memset(user_sockfd_ptr, 0, sizeof (int));
user_sockfd_ptr[0] = user_sockfd;
#ifdef DEBUG
printf("[DEBUG] Starting main menu...\n");
#endif
pthread_t thread;
int result = pthread_create(&thread, NULL, main_menu,
(void *) user_sockfd_ptr);
if (result) {
printf("Thread creation failed with return code %d\n", result);
exit(-1);
}
#ifdef DEBUG
printf("[DEBUG] New main menu thread started.\n");
#endif
}
close(lis_sockfd);
pthread_exit(NULL);
return 0;
}
If you wish to reproduce the error, you could compile the code using the following lines
g++ client.cpp -o client -std=c++14 -pthread
g++ server.cpp -o server -std=c++14 -pthread
and run both without any arguments. The client is set to connect on "localhost".
I would be really glad if anyone could help me out with this.
I recomment getting rid of the SIGPIPE signal itself.
signal(SIGPIPE, SIG_IGN);
Now, write()s on killed sockets will simply return -1. It should be easier to deal with that, instead of an asynchronous signal.
If you need SIGPIPE for other reasons, replace write()s with sendto()s with the MSG_NOSIGNAL option. See the sendto(2) manual page for more information.
You have UB. &(buffer[0]) will fail if the number of bytes read is 0 (which I believe will happen if client disconnects). You should test for 0 and return early before building your string.
Also you do not return after finding errors so you build your string from bad data in case of errors.
Maybe something more like:
std::string receive_string(int sockfd)
{
uint32_t stringLen;
int n = recv(sockfd, &stringLen, sizeof (uint32_t), 0);
if (n < 0) {
close(sockfd);
// exit early
throw std::runtime_error("Error receiving message(string size): "
+ std::string(std::strerror(errno)));
}
// test for zero
if(!n)
return {}; // empty string
stringLen = ntohl(stringLen);
std::vector<uint8_t> buffer(stringLen);
// buffer.resize(stringLen, 0x00);
//get string
n = recv(sockfd, &(buffer[0]), stringLen, 0);
if (n < 0) {
close(sockfd);
// exit early
throw std::runtime_error("Error receiving message(string): "
+ std::string(std::strerror(errno)));
}
// only build string if no errors
return {buffer.begin(), buffer.begin() + n};
}
static void timerHandler(int sig, siginfo_t *si, void *uc)
{
timer_t *tidp;
tidp = si->si_value.sival_ptr;
if (*tidp == firstTimerID)
TASK1(Task2ms_Raster);
else if (*tidp == secondTimerID)
TASK2(Task10ms_Raster);
else if (*tidp == thirdTimerID)
TASK3(Task100ms_Raster);
}
static int makeTimer(char *name, timer_t *timerID, int expireMS, int intervalMS)
{
//sigset_t mask;
struct sigevent te;
struct itimerspec its;
struct sigaction sa;
int sigNo = SIGRTMIN;
/* Set up signal handler. */
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = timerHandler;
sigemptyset(&sa.sa_mask);
if (sigaction(sigNo, &sa, NULL) == -1)
{
perror("sigaction");
}
/* Set and enable alarm */
te.sigev_notify = SIGEV_SIGNAL;
te.sigev_signo = sigNo;
te.sigev_value.sival_ptr = timerID;
timer_create(CLOCK_REALTIME, &te, timerID);
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = intervalMS * 1000000;
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = expireMS * 1000000;
timer_settime(*timerID, 0, &its, NULL);
return 1;
}
int CreateSocket()
{
socklen_t len = sizeof(client);
// Socket creation for UDP
acceptSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (acceptSocket == -1)
{
printf("Failure: socket creation is failed, failure code\n");
return 1;
}
else
{
printf("Socket started!\n");
}
//non blocking mode
/* rc = ioctl(acceptSocket, FIONBIO, (char *)&flag);
if (rc < 0)
{
printf("\n ioctl() failed \n");
return 0;
}*/
//Bind the socket
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
rc = bind(acceptSocket, (struct sockaddr*) &addr, sizeof(addr));
if (rc == -1)
{
printf("Failure: listen, failure code:\n");
return 1;
}
else
{
printf("Socket an port %d \n", port);
}
if (acceptSocket == -1)
{
printf("Fehler: accept, fehler code:\n");
return 1;
}
else
{
while (rc != -1)
{
rc = recvfrom(acceptSocket, buf, 256, 0, (struct sockaddr*) &client,
&len);
if (rc == 0)
{
printf("Server has no connection..\n");
break;
}
if (rc == -1)
{
printf("something went wrong with data %s", strerror(errno));
break;
}
XcpIp_RxCallback((uint16) rc, (uint8*) buf, (uint16) port);
makeTimer("First Timer", &firstTimerID, 2, 2); //2ms
makeTimer("Second Timer", &secondTimerID, 10, 10); //10ms
makeTimer("Third Timer", &thirdTimerID, 100, 100); //100ms
while (1)
;;
}
}
close(acceptSocket);
return 0;
}
int main()
{
Xcp_Initialize();
CreateSocket();
return 2;
}
void XcpApp_IpTransmit(uint16 XcpPort, Xcp_StatePtr8 pBytes, uint16 numBytes)
{
if ((long) XcpPort == port)
{
sentbytes = sendto(acceptSocket, (char*) pBytes, (long) numBytes, 0,
(struct sockaddr*) &client, sizeof(client));
}
XcpIp_TxCallback(port, (uint16) sentbytes);
}
I am working on a client and server architecture. Server code is shown above and I created a socket to recieve the request from the client via the ip address and port number. Server is waiting for a request from the client and send a response back to the client. when ever it recieves data from the client, it should call the timer task (i.e callBackTimers in my code), For that I also created timer to call the task for every 2ms, 10ms and 100ms.
My QUESTION : In debug mode - control is reaching the maketimer function call but it is not running automatically (I did not add any break point). it is halting at maketimer3. How to make it run without halting ??
As I answered in your previous question, this probably has to do with your CreateSocket function, namely:
while(rc!=-1)
{
rc=recvfrom(acceptSocket,buf, 256, 0, (struct sockaddr*) &client, &len);
if(rc==0)
{
printf("Server has no connection..\n");
break;
}
if(rc==-1)
{
printf("something went wrong with data %s", strerror(errno));
break;
}
XcpIp_RxCallback( (uint16) rc, (uint8*) buf, (uint16) port );
makeTimer("First Timer", &firstTimerID, 2, 2); //2ms
makeTimer("Second Timer", &secondTimerID, 10, 10); //10ms
makeTimer("Third Timer", &thirdTimerID, 100, 100); //100ms
while(1)
;;
}
You are creating new timers every time through this loop. You never delete them. There is a limit to how many timers you can create. From man (2) timer_create:
The kernel preallocates a "queued real-time signal" for each timer created using timer_create(). Consequently, the number of timers is limited by the RLIMIT_SIGPENDING resource limit (see setrlimit(2)).
You aren't checking the return code status of timer_create and my guess is that you run out of timers and then are just failing after that.
(BTW, not sure what the while(1);; is suppose to do. I understand the frustration you must be feeling but this is becoming something of a moving target.)
Here is a hastily (but I think accurate) chopped up version of your code. Because of your while(1); in CreateSocket it is just going to create the 3 timers. If you run it you will see that TASKS1/2/3 run. This, in itself, is not your problem.
#define _POSIX_C_SOURCE 199309
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
timer_t firstTimerID, secondTimerID, thirdTimerID;
void TASK1() {printf("task 1\n");}
void TASK2() {printf("task 2\n");}
void TASK3() {printf("task 3\n");}
static void timerHandler(int sig, siginfo_t *si, void *uc)
{
timer_t *tidp;
tidp = si->si_value.sival_ptr;
if (*tidp == firstTimerID)
TASK1();
else if (*tidp == secondTimerID)
TASK2();
else if (*tidp == thirdTimerID)
TASK3();
}
static int makeTimer(char *name, timer_t *timerID, int expireMS, int intervalMS)
{
//sigset_t mask;
struct sigevent te;
struct itimerspec its;
struct sigaction sa;
int sigNo = SIGRTMIN;
/* Set up signal handler. */
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = timerHandler;
sigemptyset(&sa.sa_mask);
if (sigaction(sigNo, &sa, NULL) == -1)
{
perror("sigaction");
}
/* Set and enable alarm */
te.sigev_notify = SIGEV_SIGNAL;
te.sigev_signo = sigNo;
te.sigev_value.sival_ptr = timerID;
timer_create(CLOCK_REALTIME, &te, timerID);
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = intervalMS * 1000000;
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = expireMS * 1000000;
timer_settime(*timerID, 0, &its, NULL);
return 1;
}
int CreateSocket()
{
int rc = 5;
while (rc != -1)
{
makeTimer("First Timer", &firstTimerID, 2, 2); //2ms
makeTimer("Second Timer", &secondTimerID, 10, 10); //10ms
makeTimer("Third Timer", &thirdTimerID, 100, 100); //100ms
while (1);;
}
return 0;
}
int main()
{
CreateSocket();
return 2;
}
Take care of the loop issue and see where you have to go from there. Create the 3 timers. If you only want them to go off once per socket read then either don't have an interval value so they don't repeatedly go off or reset the timers (i.e. zero out the value/interval values) after the first time they go off. But in either case, you should reuse them.