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().
Related
I'm trying to test with OpenSSL DTLS by making a program that creates a client and server socket to echo strings between the sockets; However, when I try to test out DTLSv1_Listen() function my program seems to pause even when I am not trying connecting or sending data between the sockets. note: I am using a post 1.0.2 OpenSSL which is after DTLSv1_Listen() was rewritten.
Here is my complete C++ winsock specific code:
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
//#include <openssl/applink.c>
#include <string>
#pragma comment(lib, "Ws2_32.lib")
struct DTLSStuff { //struct to contain DTLS object instances
SSL_CTX *ctx;
SSL *ssl;
BIO *bio;
};
void DTLSErr() { //DTLS error reporting
ERR_print_errors_fp(stderr);
exit(1);
}
int newSocket(sockaddr_in addr) { //creates a socket and returns the file descriptor //TODO expand for multi-platform
WSADATA wsaData;
int fd;
int iResult;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); //Initialize Winsock
if (iResult != 0) { printf("WSAStartup failed: %d\n", iResult); exit(1); }
fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("Unable to create socket"); exit(1); } //create socket
printf("New Socket: %i\n", fd);
if (bind(fd, (struct sockaddr *)&addr, sizeof(sockaddr)) < 0) { printf("bind failed with error %u\n", WSAGetLastError()); exit(1); }
return fd; //file descriptor
}
void InitCTX(SSL_CTX *ctx, bool IsClient) { //Takes a ctx object and initializes it for DTLS communication
if (IsClient) {
if(SSL_CTX_use_certificate_chain_file(ctx, "client-cert.pem") < 0) { printf("Failed loading client cert");}
if(SSL_CTX_use_PrivateKey_file(ctx, "client-key.pem", SSL_FILETYPE_PEM) < 0) { printf("Failed loading client key"); }
}
else {
if (SSL_CTX_use_certificate_chain_file(ctx, "server-cert.pem") < 0) { printf("Failed loading client cert"); }
if (SSL_CTX_use_PrivateKey_file(ctx, "server-key.pem", SSL_FILETYPE_PEM) < 0) { printf("Failed loading client key"); }
}
//SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cert); //omitted for testing
//SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie); //omitted for testing
//SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie); //omitted for testing
SSL_CTX_set_read_ahead(ctx, 1);
}
int main() { //creates client and server sockets and DTLS objects. TODO: have client complete handshake with server socket and send a message and have the server echo it back to client socket
BIO_ADDR *faux_addr = BIO_ADDR_new(); // for DTLSv1_listen(), since we are this is both client and server (meaning client address is known) it is only used to satisfy parameters.
ERR_load_BIO_strings();
SSL_load_error_strings();
SSL_library_init();
//Set up addresses
sockaddr_in client_addr;
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(25501);
client_addr.sin_addr.s_addr = INADDR_ANY;
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(25500);
server_addr.sin_addr.s_addr = INADDR_ANY;
//*********CLIENT
DTLSStuff ClientInf;
ClientInf.ctx = SSL_CTX_new(DTLSv1_client_method());
InitCTX(ClientInf.ctx,true);
int ClientFD = newSocket(client_addr);
ClientInf.bio = BIO_new_dgram(ClientFD, BIO_NOCLOSE);
ClientInf.ssl = SSL_new(ClientInf.ctx);
//SSL_set_options(ClientInf.ssl, SSL_OP_COOKIE_EXCHANGE); //omitted for testing
SSL_set_bio(ClientInf.ssl, ClientInf.bio, ClientInf.bio);
//*********SERVER
DTLSStuff ServerInf;
ServerInf.ctx = SSL_CTX_new(DTLSv1_server_method());
InitCTX(ServerInf.ctx,false);
int ServerFD = newSocket(server_addr);
ServerInf.bio = BIO_new_dgram(ServerFD, BIO_NOCLOSE);
ServerInf.ssl = SSL_new(ServerInf.ctx);
//SSL_set_options(ServerInf.ssl, SSL_OP_COOKIE_EXCHANGE); //omitted for testing
SSL_set_bio(ServerInf.ssl, ServerInf.bio, ServerInf.bio);
printf("Listen attempt...\n");
int ret = DTLSv1_listen(ServerInf.ssl, faux_addr);
if (ret < 0) { DTLSErr(); }
printf("this print should occur, but it never does");
exit(1);
}
I expect the results to be as follow:
NewSocket: 356
NewSocket: 360
Listen attempt...
this print should occur but it never does
However when running the program it never prints the last line. The program seems to respond as I am able to cancel the executable by ctrl+c so I am assuming it has not crashed or froze, but aside from that I am at a loss. My understanding is that the method should return 0 if nothing happens, >1 if it heard a clienthello, and <0 if an error occurred.
Also, a somewhat related question: Since DTLSv1_Listen() requires a BIO_ADDR to store the incoming requests address does that mean that separate client and servers programs will both require 2 sockets if they want to be able to both send and listen? Normally UDP clients and servers only need a single socket, but I cannot seem to figure a design to retain this with OpenSSL's DTLS.
I thank you for your time.
I don't see anywhere in your code where you set the socket to be non-blocking. In the default blocking mode when you attempt to read from the socket your program will pause until data has arrived. If you don't want that then make sure your set the appropriate option (I'm not a Windows programmer, but ioctlsocket seems to do the job: https://msdn.microsoft.com/en-us/library/windows/desktop/ms738573(v=vs.85).aspx)
does that mean that separate client and servers programs will both require 2 sockets if they want to be able to both send and listen
When using DTLSv1_listen() you are using the socket in an unconnected state, so you may receive UDP packets from multiple clients. DTLS is connection based so once DTLSv1_listen() returns successfully you are supposed to create a "connected" socket to the client address. So you have one socket for listening for new connections, and one socket per client communicating with your server.
I have UDP program in matlab in one machine and UDP in cpp in other machine. I am able to send data from cpp code to matlab , by running cpp code as client and matlab code as server. When I tried running matlab as client and cpp as server I am not able to send the data to cpp.In Both the above cases programms are running in two different machines.I tried matlab as client and cpp as server in same machine then its worked.
my cpp code
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "port.h"
#define BUFSIZE 2048
int
main(int argc, char **argv)
{
struct sockaddr_in myaddr; /* our address */
struct sockaddr_in remaddr; /* remote address */
socklen_t addrlen = sizeof(remaddr); /* length of addresses */
int recvlen; /* # bytes received */
int fd; /* our socket */
unsigned char buf[BUFSIZE]; /* receive buffer */
/* create a UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("cannot create socket\n");
return 0;
}
/* bind the socket to any valid IP address and a specific port */
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(SERVICE_PORT);
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror("bind failed");
return 0;
}
/* now loop, receiving data and printing what we received */
for (;;) {
printf("waiting on port %d\n", SERVICE_PORT);
recvlen = recvfrom(fd, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
printf("received %d bytes\n", recvlen);
if (recvlen > 0) {
buf[recvlen] = 0;
printf("received message: \"%s\"\n", buf);
}
}
/* never exits */
}
Posting the answer from the comments here for visibility:
Since the programs work when run on the same computer, but not when run on separate computers, that points to a firewall issue (meaning the computer is blocking inbound traffic). In Linux, iptables (that's what the firewall is called) can be temporarily disabled per the instructions at: https://www.cyberciti.biz/faq/turn-on-turn-off-firewall-in-linux/
If that solves the problem, don't forget to turn iptables back on. Then just add an exception in iptables for your program similar to these instructions: https://help.ubuntu.com/community/IptablesHowTo#Allowing_Incoming_Traffic_on_Specific_Ports
Hello everyone.
I'm trying to use Windows sockets to send and receive UDP packets (in C++).
It worked well until three days ago, when the program stopped behaving properly.
To summarize the situation:
When calling WSAPoll() on my socket, it always returns my socket updated with EVERY revents possible (corresponding to every events I gave the pollfd), even if there is no server launched.
When calling recvfrom() and no server is launched, it returns SOCKET_ERROR with error code 10054(*).
When calling recvfrom() and a server is launched, it works properly - blocks until it receives something.
The behavior is the same whether I try to connect to localhost or to a distant host.
(*) I investigated this error. In UDP, it means that there is an ICMP problem. ("On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.").
I indeed call sendto() before recvfrom(), so the problem's not here.
I tried to put down my firewall to see if it changed anything, but it didn't. I also tried to put down every network flowing through my PC. In this state I managed to get the program to work for a few minutes, but when I enabled the networks it stopped working again. I tried to repeat the process but it would not work anymore.
I tried compiling with both visual studio (2015) and MinGW.
I tried on another computer too (under Windows 7, mine has Windows 8.1), to no avail.
Here is a simple test file which does not work on my computer.
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x501
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <vector>
#include <iostream>
int main() {
int clientSock;
char buf[100];
int serverPort;
/* Initializing WSA */
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
/* I create my socket */
struct addrinfo specs;
struct addrinfo *addr = new addrinfo;
ZeroMemory(&specs, sizeof(specs));
specs.ai_family = AF_INET;
specs.ai_socktype = SOCK_DGRAM;
specs.ai_flags = 0;
getaddrinfo("127.0.0.1", "2324", &specs, &addr);
clientSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
/* I get the server's address */
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddr.sin_port = htons(2324);
int len = sizeof(struct sockaddr);
/* I'll poll & recvfrom on my socket */
std::vector<pollfd> fds;
pollfd fd;
fd.fd = clientSock;
fd.events = POLLRDNORM;
fd.revents = -1;
fds.push_back(fd);
while(1) {
memset(buf,0,sizeof(buf));
printf("\nClient--->: ");
gets(buf);
/* It's UDP, so it doesn't matter if there is someone to receive the packet */
sendto(clientSock, buf, strlen(buf), 0, (sockaddr*)&serverAddr ,len);
memset(buf,0,sizeof(buf));
int ret;
/* Always returns "1" */
if ((ret = WSAPoll(fds.data(), 1, 0)) > 0) {
std::cout << ret;
/* Always returns "-1" */
std::cout << recvfrom(clientSock,buf,sizeof(buf),0, (sockaddr*)&serverAddr,&len) << std::endl;
printf("\n--->From the server: ");
printf("%s",buf);
}
}
closesocket(clientSock);
WSACleanup();
return 0;
}
Two questions:
Why does WSAPoll() always returns an updated socket, even if there wasn't any interaction with it ?
Why does recvfrom() return this error and how can I fix it ? I suppose it comes from my computer. I tried allowing ICMP through my firewall but it didn't change anything, maybe I did something wrong ?
Edit: I fixed my main program (not shown here because it is way too large) by just ignoring any "error 10054" I received. Now it works the same way it does on Unix.
Still, it is not really a solution (ignoring an error code... meh) and if anyone knows why I get the "ICMP Port Unreachable" error when calling sendto(), I'd be glad to hear about it.
In Windows, if host A use UDP socket and call sendto() to send something to host B, but B doesn't bind any port so that B doesn't receive the message, and then host A call recvfrom() to receive some message, recvfrom() will failed, and WSAGetLastError() will return 10054.
It's a bug of Windows. If UDP socket recv a ICMP(port unreachable) message after send a message, this error will be stored, and next time call recvfrom() will return this error.
There are 2 ways to solve this problem:
Make sure host B has already bound the port you want to send to.
Disable this error by using following code:
#include <Winsock2.h>
#include <Mstcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
BOOL bNewBehavior = FALSE;
DWORD dwBytesReturned = 0;
WSAIoctl(iSock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL);
Reference:
http://www.cnblogs.com/cnpirate/p/4059137.html
I have stripped down the Authors code and included the fix of simmerlee. This provides an simpler way to reproduce the error:
#include "stdafx.h"
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
void testCase(bool fixed)
{
int clientSock;
char rcvBuf[100];
// create socket
clientSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(fixed)
{
BOOL bNewBehavior = FALSE;
DWORD dwBytesReturned = 0;
WSAIoctl(clientSock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL);
}
// bind socket
struct sockaddr_in clientAddr;
clientAddr.sin_family = AF_INET;
clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
clientAddr.sin_port = htons(61234);
int sizeClientAddr = sizeof(clientAddr);
bind(clientSock, (sockaddr*) &clientAddr, sizeClientAddr);
struct sockaddr_in serverAddr = clientAddr;
serverAddr.sin_port = htons(2324); // change port where nobody listens
int sizeServerAddr = sizeof(struct sockaddr);
int lasterror = 0;
int status = 0;
// send where nobody is listening
printf("Send to nowhere--->:\n");
/* It's UDP, so it doesn't matter if there is someone to receive the packet */
status =sendto(clientSock, "Message", 7, 0, (sockaddr*)&serverAddr, sizeServerAddr);
lasterror = WSAGetLastError();
printf("sendto return %d (lasterror %d)\n", status, lasterror);
// recvfrom with "failing" sendto before.
// fixed: This should block.
// unfixed: WSAGetLastError is 10054
memset(rcvBuf, 0, sizeof(rcvBuf));
status = recvfrom(clientSock, rcvBuf, sizeof(rcvBuf), 0, (sockaddr*)&serverAddr, &sizeServerAddr);
lasterror = WSAGetLastError();
printf("recvfrom return %d (lasterror %d)\n", status, lasterror);
printf("--->From the server: -%s-\n", rcvBuf);
closesocket(clientSock);
}
int _tmain(int argc, _TCHAR* argv[])
{
/* Initializing WSA */
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
printf("##### UNFIXED\n");
testCase(false);
printf("##### FIXED\n");
testCase(true);
WSACleanup();
// pause
char buf[100];
gets(buf);
return 0;
}
This should return:
##### UNFIXED
Send to nowhere--->:
sendto return 7 (lasterror 0)
recvfrom return -1 (lasterror 10054)
--->From the server: --
##### FIXED
Send to nowhere--->:
sendto return 7 (lasterror 0)
and then block.
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 writing some simple client/server code using UDP. The program works fine, but if I only start the client, the recvfrom method does not block. However, when I remove the sendto method, recvfrom starts to block. Any idea of what is going on?
Here is the client side code:
int server_length; /* Length of server struct */
char send_buffer[256] = "hi"; /* Data to send */
time_t current_time; /* Time received */
while(true)
{
/* Tranmsit data to get time */
server_length = sizeof(struct sockaddr_in);
if (sendto(m_oSocket, send_buffer, (int)strlen(send_buffer) + 1, 0, (struct sockaddr *)&m_oServer, server_length) == -1)
{
fprintf(stderr, "Error transmitting data.\n");
continue;
}
/* Receive time */
if (recvfrom(m_oSocket, (char *)¤t_time, (int)sizeof(current_time), 0, (struct sockaddr *)&m_oServer, &server_length) < 0)
{
fprintf(stderr, "Error receiving data.\n");
continue;
}
/* Display time */
printf("Current time: %s\n", ctime(¤t_time));
Sleep(1000);
}
And here is the initialization:
unsigned short m_iPortnumber;
struct sockaddr_in m_oServer;
struct sockaddr_in m_oClient;
SOCKET m_oSocket;
WSADATA w; /* Used to open Windows connection */
int a1, a2, a3, a4; /* Server address components in xxx.xxx.xxx.xxx form */
a1 = 192;
a2 = 168;
a3 = 2;
a4 = 14;
m_iPortnumber = 52685;
/* Open windows connection */
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
/* Open a datagram socket */
m_oSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (m_oSocket == INVALID_SOCKET)
{
fprintf(stderr, "Could not create socket.\n");
WSACleanup();
exit(0);
}
/* Clear out server struct */
memset((void *)&m_oServer, '\0', sizeof(struct sockaddr_in));
/* Set family and port */
m_oServer.sin_family = AF_INET;
m_oServer.sin_port = htons(m_iPortnumber);
/* Set server address */
m_oServer.sin_addr.S_un.S_un_b.s_b1 = (unsigned char)a1;
m_oServer.sin_addr.S_un.S_un_b.s_b2 = (unsigned char)a2;
m_oServer.sin_addr.S_un.S_un_b.s_b3 = (unsigned char)a3;
m_oServer.sin_addr.S_un.S_un_b.s_b4 = (unsigned char)a4;
/* Clear out client struct */
memset((void *)&m_oClient, '\0', sizeof(struct sockaddr_in));
/* Set family and port */
m_oClient.sin_family = AF_INET;
m_oClient.sin_addr.s_addr=INADDR_ANY;
m_oClient.sin_port = htons(0);
/* Bind local address to socket */
if (bind(m_oSocket, (struct sockaddr *)&m_oClient, sizeof(struct sockaddr_in)) == -1)
{
fprintf(stderr, "Cannot bind address to socket.\n");
closesocket(m_oSocket);
WSACleanup();
exit(0);
}
There are a variety of ways that sendto can fail. Some, such as arp failure, will cause an error during sendto. Other, such as ICMP port unreachable, may be reported when you next use the socket.
Your recvfrom call could actually be fetching the ICMP packet sent in response to your outgoing packet.
Does a second recvfrom block as expected?
Socket required to be set BLOCKING/NON-BLOCKING.
Set BLOCKING
int nMode = 0; // 0: BLOCKING
if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR)
{
closesocket(SendingSocket);
WSACleanup();
return iRet;
}
Set NON-BLOCKING
int nMode = 1; // 1: NON-BLOCKING
if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR)
{
closesocket(SendingSocket);
WSACleanup();
return iRet;
}
It looks like you're setting up the server socket and the client socket the same way. The initialization looks good for a server, but for the client, you'll want to bind to port 0.
In fact, for both of them you can do INADDR_ANY (IP 0.0.0.0), which doesn't bind to a specific interface, but instead allows any connection on the correct port.