UDP recvfrom not working - c++

I have UDP Server program which receives data from port 7888. The server code is below.
//UDPIPV4Server.h
#pragma once
#include <iostream>
#include <string>
#include <winsock2.h>
#include <windows.h>
#include <Ws2tcpip.h>
using std::string;
using std::cout;
using std::endl;
using std::cerr;
class UDPIPV4Server
{
public:
UDPIPV4Server();
~UDPIPV4Server(void);
UINT type;
string mac_address;
UINT port;
int socket_var;
struct sockaddr_in si_server, si_client;
int Config(void);
int RecvData(char* recv_buffer, int buf_size,string *ip_addr);
};
//UDPIPV4Server.cpp
int UDPIPV4Server::Config(void) {
WSADATA wsadata;
int error = WSAStartup(0X0202, &wsadata);
if(error) {
cerr<<"UdpIPV4Server.cpp:- WSAStartup failed"<<endl;
return -1;
}
if ((socket_var = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
cerr<<"UdpIPV4Server.cpp:- socket function failed"<<endl;
return -1;
}
memset((char *) &si_server, 0, sizeof(si_server));
si_server.sin_family = AF_INET;
si_server.sin_port = htons(7888);
char host[NI_MAXHOST] = "10.8.0.2";
if(inet_pton(AF_INET, host, &si_server.sin_addr) != 1) {
cerr<<"UdpIPV4Server.cpp: inet_pton() failed\n";
return -1;
}
if(bind(socket_var,(struct sockaddr *)&si_server,sizeof(si_server)) == -1) {
cerr<<"UdpIPV4Server.cpp:- bind failed: "<<endl;
return -1;
}
return 0;
}
//recv data from the UDP client
//recv_buffer - [out] receive buffer
//buf_size - [in] size of receive buffer in bytes
//ip_addr - [out] ip address of the remote client
int UDPIPV4Server::RecvData(char* recv_buffer, int buf_size, string *ip_addr) {
int recv_len;
cout<<"waiting for data\n";
memset((char*)&si_client, 0, sizeof(struct sockaddr_in));
int si_client_len = sizeof(si_client);
if((recv_len = recvfrom(socket_var, recv_buffer, buf_size, 0, (struct sockaddr *)&si_client, &si_client_len)) == -1) {
cerr<<"udpipv4server.cpp:- recvfrom failed"<<endl;
return recv_len;
}
char client_addr[INET_ADDRSTRLEN];
cout<<"Received packets from "<<inet_ntoa(si_client.sin_addr)<<":"<<ntohs(si_client.sin_port)<<endl;
*ip_addr = inet_ntoa(si_client.sin_addr);
return recv_len;
}
//main.cpp
#include "UDPIPV4Server.h"
int main() {
UDPIPV4Server udp_server;
udp_server.Config();
char recv_frame_buffer[65534] = "";
memset(recv_frame_buffer,0,sizeof(recv_frame_buffer));
int retval;
string ip_addr;
if((retval = udp_server.RecvData(recv_frame_buffer,sizeof(recv_frame_buffer),&ip_addr)) == -1) {
cerr<<"ReceiverCommModule:- Error in receving data"<<endl;
continue;
}
}
The above program receives data on 10.8.0.2:7888. But this code is not working when data is received. I have checked with wireshark, the data is being received at 10.8.0.2:7888. But socket is unable to read the data from the port.The UDPIPV4Server.config() function passed successfully. But the UDPIPV4Server.RecvData() is not returning. The UDP recvfrom is waiting as such there is no data received. Is it anything wrong with the code? Thank you.

I had the same issue. in UDP, recvfrom behaves as if no data were available dispite wireshark confirmed that a valid UDP packet arrived on the correct port. It happens on my compagny's computer but it works fine on my personnal one. I guess this is linked to windows fire wall or antivir that filters incoming packets if the associated port is not allowed for your software. I noticed that recvfrom works once, just after having sent packet through the same port. May be this is linked to my computer's config.

Related

Data gets cut off when send through a tcp socket in c/c++

Long messages get cut off when I send them through a tcp socket. It differs depending on the destination. When sending and receiving locally on my machine, all goes through. When sending and receiving locally on my server, it gets cut off after the 21846th byte consistently. When sending from my machine to the server, it gets cut off at the 1441th byte consistently. The server is in Stockholm and I'm in the UK. The same problem is also present when the client is on Windows and uses Windows' networking code.
Here the client is supposed to send 29 999 zeros and a null terminator, receive them and print them. When I counted them with wc, I got the figures of actual bytes that I received. So the figures represent a two-way transfer but from testing I can say that the problem has the same properties one-way.
The read/write functions are blocking as far as I can tell, so the problem is not that the data has not arrived fully before the functions exit - a problem described in the man page.
How can I fix this?
Go to the bottom to see solution
Here's the code that I used to test this:
server/main.cpp
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include "aes/aes.hpp"
#include "network.hpp"
#include <thread>
using namespace std;
int main()
{
int server_socket = InitServerSocket(26969);
std::cout << "Listening..." << std::endl;
while (true) {
// accept incoming connections - blocking
int client_socket = accept(server_socket, NULL, NULL);
if (client_socket < 0) {
std::cerr << "Unable to accept";
close(server_socket);
return 1;
}
char long_text[30000];
read(client_socket, long_text, 30000);
std::cout << long_text << std::endl;
write(client_socket, long_text, 30000);
close(client_socket);
}
return 0;
}
InitServerSocket():
int InitServerSocket(int port)
{
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
int server_socket;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
perror("Unable to create socket");
_exit(1);
}
int result = bind(
server_socket,
(struct sockaddr*)&server_address,
sizeof(server_address));
if (result < 0) {
perror("Unable to bind");
_exit(1);
}
if (listen(server_socket, 1000) < 0) {
perror("Unable to listen");
_exit(1);
}
return server_socket;
}
client/main.cpp
#include <arpa/inet.h>
#include <iostream>
#include <netdb.h>
#include <string.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include "network.hpp"
using namespace std;
int main()
{
int socket = ConnectToHost("70.34.195.74", 26969);
char long_text[30000];
for (int i = 0; i < 30000; i++)
long_text[i] = '0';
long_text[29999] = '\0';
write(socket, long_text, 30000);
read(socket, long_text, 30000);
std::cout << long_text << std::endl;
CloseConnection(socket);
return 0;
}
ConnectToHost():
int ConnectToHost(char* IPAddress, int PortNo)
{
// create a socket
int network_socket; // socket descriptor ~= pointer ~= fd
network_socket = socket(AF_INET, SOCK_STREAM, 0);
// specify a destination address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET; // specify protocol
server_address.sin_port = htons(PortNo); // specify port
// server_address.sin_addr.s_addr = a.s_addr; // specify resolved ip
server_address.sin_addr.s_addr = inet_addr(IPAddress);
// connect
int connection_status = connect(
network_socket,
(struct sockaddr*)&server_address,
sizeof(server_address));
if (connection_status == -1)
std::cout << "Failed to conect to remote host\n";
return network_socket;
}
Solution:
Here are the wrapper functions I wrote to fix the problem:
int Send(int soc, char* buffer, int size)
{
int ret = -1;
int index = 0;
do {
ret = write(soc, buffer + index, size - index);
index += ret;
} while (ret > 0);
if (ret == -1)
return -1;
else
return 1;
};
int Recv(int soc, char* buffer, int size)
{
int ret = -1;
int index = 0;
do {
ret = read(soc, buffer + index, size - index);
index += ret;
} while (ret > 0);
if (ret == -1)
return -1;
else
return 1;
};
write(client_socket, long_text, 30000);
You have no guarantees, whatsoever, that all 30000 bytes get written, even with blocking sockets. You must check the write()'s return value to determine how many bytes were actually written, then implement the required logic to try again, with whatever's left to be written, and proceed in this manner until all 30000 bytes get written to the socket. This is how sockets always work.
read(socket, long_text, 30000);
Same thing here, you must check the returned value. If the socket has only a hundred bytes of unread data waiting you'll get these 100 bytes and read() will return 100. If there's nothing unread from a blocking socket, read() will block. If the socket ends up receiving a packet with 1 byte, read() returns 1, which tells you that only 1 byte was read.
How can I fix this?
You must always check what every read() and write() returns, and proceed accordingly. If you need to read or write more data from the socket, then try again, and do that.
so the problem is not that the data has not arrived fully before
the functions exit - a problem described in the man page.
The man page also describes what the returned value from read() and write() means: a negative value indicates an error, a positive value indicates how many bytes were actually read or written. Only reading and writing to regular files guarantees that the requested number of bytes will be read or written (unless reading reaches the end of the file).

TCP Packet Encode/Decode

I'm learning c++ and coming from a Network Engineer background, and it is fun for me to program something that I'm familiar with it on the network side. I started creating a BGP speaker.
Here is my environment:
[mybgp]<------------TCP-Port-179------------->[bird]
Here is my current code.
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#define BIND_ADDR INADDR_ANY
#define BIND_PORT htons(179)
int createServerSocket(){
//Create Socket
int serverSocket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
if (serverSocket < 0) {
fprintf(stderr, "socket(): %s\n", strerror(errno));
return 1;
}
return serverSocket;
}
int createBind(const int &serverSocket, sockaddr_in &serverAddr){
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = BIND_PORT;
serverAddr.sin_addr.s_addr = INADDR_ANY;
int bind_ret = bind(serverSocket, (sockaddr *) &serverAddr, sizeof(serverAddr));
// if (bind(serverSocket, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1) {
// std::cerr << "Can't bind to ip/port";
// return -2;
// }
if (bind_ret < 0) {
fprintf(stderr, "bind(): %s\n", strerror(errno));
close(serverSocket);
return 1;
}
return bind_ret;
}
int createListener(const int &serverSocket){
int amount;
int listen_ret = listen(serverSocket, 3);
if (listen_ret < 0) {
fprintf(stderr, "listen(): %s\n", strerror(errno));
close(serverSocket);
return 1;
}
return listen_ret;
}
int acceptConnect(const int &serverSocket, sockaddr_in &clientAddr){
fprintf(stderr, "waiting for any client...\n");
char ip_str[INET_ADDRSTRLEN];
socklen_t caddr_len = sizeof(clientAddr);
int serverConn = accept(serverSocket, (sockaddr *) &clientAddr, &caddr_len);
if (serverConn < 0) {
fprintf(stderr, "accept(): %s\n", strerror(errno));
close(serverSocket);
close(serverConn);
return 1;
}
inet_ntop(AF_INET, &(clientAddr.sin_addr), ip_str, INET_ADDRSTRLEN);
fprintf(stderr, "accept(): new client from %s.\n", ip_str);
return serverConn;
}
int main(){
//Create Socket
int serverSocket = createServerSocket();
// declare server and client address struct
// bind socket.
sockaddr_in serverAddr, clientAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
int bind_ret = createBind(serverSocket, serverAddr);
// listening for connection
int listen_ret = createListener(serverSocket);
int serverConn = acceptConnect(serverSocket, clientAddr);
// we only do one at a time, no new client.
char buffer[4048] = {0};
char valread;
valread = read( serverConn , buffer, 4048);
printf("%s\n",buffer );
close(serverSocket);
return 0;
}
My current state is that I'm able to:
Create Socket
Bind the Socket to IP
Listening
Accept a Single Connection(Single thread for now)
Received Data
At step 5, I received a gibberish TCP Message from the BGP speaker(BIRD). Knowing how the BGP Protocol works, this TCP message is in an OPEN Message Format. To establish BGP peering, mybgp and bird need to go back and for with different types of messages and agree.
For me to be able to accomplish this peering, I have to:
Decode[Received Package]
Encode[send package]
How can I decode/encode the TCP packet so I can start the process of BGP peering.

Break while()-loop using UDP

Is it possible to do some work, such as increment a counter, in a while()-loop, and then break this while()-loop with a UDP message?
I have a Raspberry Pi 4, that is setup as a UDP-server. The programming language i'm using is C++. UDP.hpp:
#pragma once
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <netdb.h>
using namespace std;
/////GLOBAL CONSTANTS/////
const int c_PORT = 8080;
class UDP
{
private:
int fdSocketUDP_; //File descriptor for UDP socket
int ClientAddressLength_; //Length of client address
struct sockaddr_in ServerAddress_; //Struct handling internet address for server
struct sockaddr_in ClientAddress_; //Struct handling internet address for client
public:
UDP(); //Initialize and bind socket
~UDP(); //Close socket
string readUDP(const int readSize); //Read via UDP protocol (Only for blocking socket)
void writeUDP(string message); //Write via UDP protocol (Only for blocking socket)
};
UDP.cpp:
#include "udp.hpp"
UDP::UDP()
{
if ((fdSocketUDP_ = socket(AF_INET, SOCK_DGRAM, 0)) < 0) //Create UDP socket
{
perror("Error - socket creation - udp.cpp");
exit(EXIT_FAILURE);
}
memset(&ServerAddress_, 0, sizeof(ServerAddress_)); //Sets ServerAddress_ to 0
memset(&ClientAddress_, 0, sizeof(ClientAddress_)); //Sets ClientAddress_ to 0
ServerAddress_.sin_family = AF_INET; //Address family, must be AF_INET = IPv4
ServerAddress_.sin_port = htons(c_PORT); //PORT number, convert PORT number to network byte order using htons()
ServerAddress_.sin_addr.s_addr = INADDR_ANY; //IP-Address of host (server IP), INADDR_ANY gets this IP Address
if (bind(fdSocketUDP_, (const struct sockaddr *)&ServerAddress_, sizeof(ServerAddress_)) < 0) //Bind the socket to ServerAddress_
{
perror("Error - socket bind - udp.cpp");
exit(EXIT_FAILURE);
}
}
UDP::~UDP()
{
close(fdSocketUDP_); //Close socket
}
string UDP::readUDP(const int readSize)
{
char readMsg[readSize] = {0}; //Read buffer
ClientAddressLength_ = sizeof(ClientAddress_);
if ((recvfrom(fdSocketUDP_, readMsg, readSize, 0, (struct sockaddr *)&ClientAddress_, (socklen_t *)&ClientAddressLength_)) < 0) //Receive data via UDP protocol
{
perror("Error - recvfrom - udp.cpp");
exit(EXIT_FAILURE);
}
string str(readMsg); //Convert char array to string
str = str.substr(0, readSize); //Make sure the string is the length of readsize
return str;
}
void UDP::writeUDP(string message)
{
//Make char array
int writeSize = message.size();
char writeMsg[writeSize + 1] = {'\0'};
//Convert string message to char array
for (int i = 0; i < writeSize; i++)
{
writeMsg[i] = message[i];
}
if ((sendto(fdSocketUDP_, writeMsg, writeSize, 0, (const struct sockaddr *)&ClientAddress_, (socklen_t)ClientAddressLength_)) < 0) //Send data via UDP protocol
{
perror("Error - sendto - udp.cpp");
exit(EXIT_FAILURE);
}
}
I have a laptop, running a Labview program. It acts as a UDP client. By sending data to the RPi from the laptop, I want to be able to break a while loop in the main()-function by sending specific data via UDP.
Let's say I send "111" data to the RPi from the laptop. The RPi then goes into a while()-loop in the main()-function, doing some work. I want the RPi to stay in this while()-loop, until I send som specific data from the Laptop. Let's say the data i want to break this while()-loop with is "999".
Is this possible using UDP?
Sure. Just set the socket non-blocking and periodically check if there's data received on the socket. If there is, check if it's a command to stop and, if so, stop. You can check every iteration of the loop or, if the loop repeats very quickly, every 10 or every 100 iterations.
I have solved my problem thanks to #Marquis of Lorne and #David Schwartz. The solution was to use fcntl and set the socket to non-blocking.
I've updated the UDP.hpp to:
#pragma once
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <netdb.h>
#include <sys/unistd.h>
#include <sys/fcntl.h>
using namespace std;
/////GLOBAL CONSTANTS/////
const int c_PORT = 8080;
class UDP
{
private:
int fdSocketUDP_; //File descriptor for UDP socket
int ClientAddressLength_; //Length of client address
struct sockaddr_in ServerAddress_; //Struct handling internet address for server
struct sockaddr_in ClientAddress_; //Struct handling internet address for client
public:
UDP(); //Initialize and bind socket
~UDP(); //Close socket
void initNonBlock(); //Initialize and bind socket (non blocking)
void initBlock(); //Initialize and bind socket (blocking)
void closeSocket(); //Close socket
string readNonBlock(const int readSize); //read via UDP protocol with non blocking socket
string readUDP(const int readSize); //Read via UDP protocol (Only for blocking socket)
void writeUDP(string message); //Write via UDP protocol (Only for blocking socket)
};
I've updated the UDP.cpp to:
#include "udp.hpp"
UDP::UDP()
{
}
UDP::~UDP()
{
closeSocket();
}
void UDP::initNonBlock()
{
if ((fdSocketUDP_ = socket(AF_INET, SOCK_DGRAM, 0)) < 0) //Create UDP socket
{
perror("Error - socket creation - udp.cpp");
exit(EXIT_FAILURE);
}
fcntl(fdSocketUDP_, F_SETFL, O_NONBLOCK); //Set to non-blocking mode
memset(&ServerAddress_, 0, sizeof(ServerAddress_)); //Sets ServerAddress_ to 0
memset(&ClientAddress_, 0, sizeof(ClientAddress_)); //Sets ClientAddress_ to 0
ServerAddress_.sin_family = AF_INET; //Address family, must be AF_INET = IPv4
ServerAddress_.sin_port = htons(c_PORT); //PORT number, convert PORT number to network byte order using htons()
ServerAddress_.sin_addr.s_addr = INADDR_ANY; //IP-Address of host (server IP), INADDR_ANY gets this IP Address
if (bind(fdSocketUDP_, (const struct sockaddr *)&ServerAddress_, sizeof(ServerAddress_)) < 0) //Bind the socket to ServerAddress_
{
perror("Error - socket bind - udp.cpp");
exit(EXIT_FAILURE);
}
}
void UDP::initBlock()
{
if ((fdSocketUDP_ = socket(AF_INET, SOCK_DGRAM, 0)) < 0) //Create UDP socket
{
perror("Error - socket creation - udp.cpp");
exit(EXIT_FAILURE);
}
memset(&ServerAddress_, 0, sizeof(ServerAddress_)); //Sets ServerAddress_ to 0
memset(&ClientAddress_, 0, sizeof(ClientAddress_)); //Sets ClientAddress_ to 0
ServerAddress_.sin_family = AF_INET; //Address family, must be AF_INET = IPv4
ServerAddress_.sin_port = htons(c_PORT); //PORT number, convert PORT number to network byte order using htons()
ServerAddress_.sin_addr.s_addr = INADDR_ANY; //IP-Address of host (server IP), INADDR_ANY gets this IP Address
if (bind(fdSocketUDP_, (const struct sockaddr *)&ServerAddress_, sizeof(ServerAddress_)) < 0) //Bind the socket to ServerAddress_
{
perror("Error - socket bind - udp.cpp");
exit(EXIT_FAILURE);
}
}
void UDP::closeSocket()
{
close(fdSocketUDP_); //Close socket
}
string UDP::readNonBlock(const int readSize)
{
char readMsg[readSize] = {0}; //Read buffer
ClientAddressLength_ = sizeof(ClientAddress_);
recvfrom(fdSocketUDP_, readMsg, readSize, 0, (struct sockaddr *)&ClientAddress_, (socklen_t *)&ClientAddressLength_);
string str(readMsg); //Convert char array to string
str = str.substr(0, readSize); //Make sure the string is the length of readsize
return str;
}
string UDP::readUDP(const int readSize)
{
char readMsg[readSize] = {0}; //Read buffer
ClientAddressLength_ = sizeof(ClientAddress_);
if ((recvfrom(fdSocketUDP_, readMsg, readSize, 0, (struct sockaddr *)&ClientAddress_, (socklen_t *)&ClientAddressLength_)) < 0) //Receive data via UDP protocol
{
perror("Error - recvfrom - udp.cpp");
exit(EXIT_FAILURE);
}
string str(readMsg); //Convert char array to string
str = str.substr(0, readSize); //Make sure the string is the length of readsize
return str;
}
void UDP::writeUDP(string message)
{
//Make char array
int writeSize = message.size();
char writeMsg[writeSize + 1] = {'\0'};
//Convert string message to char array
for (int i = 0; i < writeSize; i++)
{
writeMsg[i] = message[i];
}
if ((sendto(fdSocketUDP_, writeMsg, writeSize, 0, (const struct sockaddr *)&ClientAddress_, (socklen_t)ClientAddressLength_)) < 0) //Send data via UDP protocol
{
perror("Error - sendto - udp.cpp");
exit(EXIT_FAILURE);
}
}
Thanks to this, i was able to break the do-while loop:
udp.closeSocket();
udp.initNonBlock();
do
{
//Do something
} while (udp.readNonBlock(3).compare("153") != 0);
udp.closeSocket();
udp.initBlock();
If the message sent from the UDP client is "153", it breaks the do-while loop.

Accept() (Winsock 2) stops the program

I have a program that serves both as client and as server without multi-threading (as far as I know accept should let the program continue up until a certain connection is occurs).
The thing is, that my friend has a very similar program (not multithreaded) that also serves as both client AND server and it totally works, I'm trying to accomplish the same thing and accept() stops the program.
The code is as the following:
//main.cpp
#include <iostream>
#include "Client.h"
#include "Server.h"
#pragma comment(lib, "Ws2_32.lib")
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
Server s(6666);
Client c("127.0.0.1", 6666);
cout << "Done";
WSACleanup();
return 0;
}
Server.cpp (two variables, SOCKET _socket and struct sockaddr_in _details):
Server::Server(unsigned short Port) : _socket(0)
{
this->_socket = socket(AF_INET, SOCK_STREAM, 0);
if (_socket < 0)
throw "Invalid socket";
ZeroMemory(&this->_details, sizeof(this->_details));
this->_details.sin_family = AF_INET;
this->_details.sin_port = htons(Port);
this->_details.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if (bind(this->_socket, (const struct sockaddr*)&this->_details, sizeof(this->_details)) != 0)
{
throw "Bind Unsuccessful";
}
this->AcceptConnections();
}
void Server::AcceptConnections()
{
if (listen(this->_socket, SOMAXCONN) != 0)
throw "Listen Unsuccessful";
void* buf = NULL;
string ans("Accepted");
int client;
struct sockaddr_in client_addr;
int addrlen = sizeof(client_addr);
client = accept(this->_socket, (struct sockaddr*)&client_addr, &addrlen);
/*THIS IS WHERE THE PROGRAM STOPS... AWAITING CONNECTIONS*/
//NEVER REACHING THE CODE HERE
int recvBytes = this->Receive(buf, MY_MAX_LEN);
if (recvBytes <= 0)
{
throw "Client disconnected";
}
this->Send((void*)ans.c_str(), ans.length());
closesocket(client);
closesocket(this->_socket);
}
And client.cpp is irrelevant as it doesn't even encounter its code.
Why does this happen? How come my friend has a code with no multi-threading that has both client and server. By the way, Send and Receive are functions implemented by me.

bad file descriptor with close() socket (c++)

I'm running out of file descriptors when my program can't connect another host. The close() system call doesn't work, the number of open sockets increases. I can se it with
cat /proc/sys/fs/file-nr
Print from console:
connect: No route to host
close: Bad file descriptor
connect: No route to host
close: Bad file descriptor
..
Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <iostream>
using namespace std;
#define PORT 1238
#define MESSAGE "Yow!!! Are we having fun yet?!?"
#define SERVERHOST "192.168.9.101"
void
write_to_server (int filedes)
{
int nbytes;
nbytes = write (filedes, MESSAGE, strlen (MESSAGE) + 1);
if (nbytes < 0)
{
perror ("write");
}
}
void
init_sockaddr (struct sockaddr_in *name,
const char *hostname,
uint16_t port)
{
struct hostent *hostinfo;
name->sin_family = AF_INET;
name->sin_port = htons (port);
hostinfo = gethostbyname (hostname);
if (hostinfo == NULL)
{
fprintf (stderr, "Unknown host %s.\n", hostname);
}
name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
}
int main()
{
for (;;)
{
sleep(1);
int sock;
struct sockaddr_in servername;
/* Create the socket. */
sock = socket (PF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror ("socket (client)");
}
/* Connect to the server. */
init_sockaddr (&servername, SERVERHOST, PORT);
if (0 > connect (sock,
(struct sockaddr *) &servername,
sizeof (servername)))
{
perror ("connect");
sock = -1;
}
/* Send data to the server. */
if (sock > -1)
write_to_server (sock);
if (close (sock) != 0)
perror("close");
}
return 0;
}
Fix:
if (0 > connect (sock,
(struct sockaddr *) &servername,
sizeof (servername)))
{
perror ("connect");
}
else
write_to_server (sock);
if (close (sock) != 0)
perror("close");
It looks like the problem is in the structure of your program. Every time through your infinite loop, you're creating a new socket. I'd suggest moving this out of the loop and re-using it.
If you'd like to just fix the way you're doing it now though, use close inside the "connect" failed if statement you have now. The descriptor is allocated by the 'socket' call and only connected with the 'connect' call. By setting your 'sock' variable to -1, you're throwing away the descriptor allocated by 'socket'. Call close, then set it to -1 and you should be set.