I have a tcp server and 2 clients that want to connect to it. The way this clients will connect is that 1 of them, lets call it client1 will be all the time connected sending data and the other, client2, will eventually connect, send small amount of data and disconnect. I set O_NONBLOCK option on. The behaviour I experience is that the client that is continuosly sending data,on server side, receives one message and wait for the next connection... Here is what i tried so far(The code is the while where in any moment the client2 wants to connect and send data and disconnect):
fcntl(sockfd, F_SETFL, O_NONBLOCK);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
int flag = 0;
do {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if(newsockfd > 0){
//Sockets Layer Call: inet_ntop()
inet_ntop(AF_INET6, &(cli_addr.sin6_addr),client_addr_ipv6, 100);
printf("Incoming connection from client having IPv6 address: %s\n",client_addr_ipv6);
n = recv(newsockfd, buffer, 49,0);
if(n > 0){
send_data(argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],buffer);
memset(buffer,0,sizeof(buffer));
}
}
newsockfd2 = accept(sockfd, (struct sockaddr *) &cli_addr2, &clilen);
//Sockets Layer Call: inet_ntop()
if(newsockfd2 > 0){
inet_ntop(AF_INET6, &(cli_addr2.sin6_addr),client_addr_ipv6, 100);
printf("Incoming connection from client having IPv6 address: %s\n",client_addr_ipv6);
n2= recv(newsockfd2, buffer, 49, 0);
if(n2 > 0){
send_data(argv[1],argv[2],argv[3],argv[4],argv[5],argv[6],buffer);
memset(buffer,0,sizeof(buffer));
}
}
}while(!flag);
I also tried adding the option inside of the while and setting nonblocking on newsockfd and newsockfd2but same result.
What am I doing wrong? thanks ! :D
When a new socket is retuned from accept, you must create a new thread with this socket so that one-to-one communication will be handled in this thread. The socked doesn't have to ne non-blocking.
Related
I am working with two binaries which use UDP sockets. Process A waits for messages on a UDP socket (IP_1:PORT_1) by select(), and process B eventually sends through an UDP socket.
By some constraints out of scope, process B needs to send by a socket on (IP_1:PORT_1). Since this is the same IP:PORT pair for both processes, it is not possible to use bind(). I tried SO_REUSEADDR, but I am wondering if reusing the IP:PORT with SO_REUSEADDR for sending and receiving makes sense, or was this option conceived just for listening sockets?
process A
int nOptVal = 1;
setsockopt(UDPSocket, SOL_SOCKET, SO_REUSEADDR, &nOptVal, sizeof(nOptVal));
bind(UDPSocket, (struct sockaddr *)&addrLocal, sizeof(addrLocal));
select(fdMax+1, UDPSocket, NULL, NULL, NULL);
process B
int nOptVal = 1;
setsockopt(UDPSocket, SOL_SOCKET, SO_REUSEADDR, &nOptVal, sizeof(nOptVal));
bind(UDPSocket, (struct sockaddr *)&addrLocal, sizeof(addrLocal));
sendto(UDPSocket, buff, len, 0, (struct sockaddr *)&addrDest, sizeof(struct sockaddr));
I need to connect two programs via udp. The way this is to work is that both programs are udp servers and they send and receive on two ports like this:
programA listens on port 20037 and sends on port 20038.
programB listens on port 20038 and sends on port 20037.
Both programA and programB run on the same computer.
programA is already written and it does appear to bind its sockets as above. ie transmit port = 20038 and listen port = 20037.
I have written a udp program to be programB.
My program B binds the server socket to port 20038 which is correct.
But when programB receives a message from programA, the client socket seems to bind to some random port, eg port 10690. But I need it to bind to port 20037.
The protocol used, needs to send a simple ack message back when a message is received.
My code looks like this:
struct sockaddr_in client;
char buffer[BUFFER_SIZE];
/* Loop and get data from clients */
while (1)
{
int client_length = (int)sizeof(struct sockaddr_in);
/* Receive bytes from client */
int 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();
exit(0);
}
printf("%u bytes received from client on port %u\n", bytes_received, client.sin_port);
SendAck();
}
And SendAck() is like this:
void udpserver::SendAck() {
unsigned char acker[] = { SOM, ACK };
int length = sizeof(acker)/sizeof(acker[0]);
int client_length = (int)sizeof(struct sockaddr_in);
if (sendto(sd, (const char*)acker, length, 0, (struct sockaddr *)&client, client_length) == -1)
{
fprintf(stderr, "Error transmitting data.\n");
closesocket(sd);
WSACleanup();
exit(0);
}
else
printf("successfully sent ack to client\n");
}
I assumed that port number of client socket received would be the 20037 but it is a random number. Can I force the client socket to bind to port 20037? Because the ack message has to be sent to port 20037.
And I can't change the design of this. ProgramA will always bind to listening port 20037 and send by binding its client port to 20038. I have freedom to do whatever is required for programB.
recvfrom() reports the remote IP/port that the received packet was sent from. ProgramA is sending data from port 20038. SendAck() is calling sendto() using the client information provided by recvfrom(), which means the ACK is being sent to port 20038, not to port 20037.
It is unusual for a UDP system to send replies to a port that is different than the sending port. But so be it. You will have to tell sendto() which port to send to.
You are also not logging the sender's port correctly. The client.sin_port is expressed in network byte order. Use ntohs() to change it to host byte order when logging it. Failing to do that would account for the random number you are seeing.
Try this:
struct sockaddr_in client;
char buffer[BUFFER_SIZE];
/* Loop and get data from clients */
while (1)
{
int client_length = (int)sizeof(struct sockaddr_in);
/* Receive bytes from client */
int 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();
exit(0);
}
printf("%u bytes received from client at %s on port %u\n", bytes_received, inet_ntoa(client.sin_addr), ntohs(client.sin_port));
SendAck(&client);
}
void udpserver::SendAck(struct sockaddr_in *client)
{
struct sockaddr_in receiver;
memcpy(&receiver, client, sizeof(struct sockaddr_in));
receiver.sin_port = htons(20037);
unsigned char acker[] = { SOM, ACK };
int length = sizeof(acker)/sizeof(acker[0]);
if (sendto(sd, (const char*)acker, length, 0, (struct sockaddr *)&receiver, sizeof(struct sockaddr_in)) == -1)
{
fprintf(stderr, "Error transmitting data.\n");
closesocket(sd);
WSACleanup();
exit(0);
}
else
printf("successfully sent ack to client at %s on port %d\n", inet_ntoa(receiver.sin_addr), ntohs(receiver.sin_port));
}
Bind socket to port which you want to be used as an outbound port:
client.sin_port = htons(20037);
and then send:
sendto(sd, (const char*) acker, length, 0,
(struct sockaddr*) &client, client_length);
I want to implement a 'flexible' TCP connection where I can randomly shutdown and restart both the Server and the Client. The other one should then automatically detect the shutdown and enter try to reconnect. I successfully implemented this s.t. I can shutdown and restart the server. The client discovers the shutdown (via recv(...) == 0) and then closes the connection (it therefore closes the sockets close(this->sockfd_) and close(this->newsockfd_)).
Unfortunately I am not able to get this working the other way around. I initialize the server (using the class constructor) the following way:
tcpServer::tcpServer(int _port) {
this->sockfd_ = -1;
this->port_ = _port;
this->connected_ = false;
if ((this->sockfd_ = socket(AF_INET, SOCK_STREAM, 0)) < 0)
this->dieWithError("ERROR opening Socket");
else
printf("-> Port %d: Socket opened\n", this->port_);
// get rid of "address already in use" error message
int yes = 1;
setsockopt(this->sockfd_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
/* assign values to the fields of struct sockaddr_in */
bzero((char *) &this->serv_addr_, sizeof(this->serv_addr_));
this->serv_addr_.sin_family = AF_INET;
this->serv_addr_.sin_port = htons(this->port_);
this->serv_addr_.sin_addr.s_addr = INADDR_ANY;
/* bind the socket to an address */
if (bind(this->sockfd_, (struct sockaddr *) &this->serv_addr_, sizeof(this->serv_addr_)) < 0) {
printf("-> Port %d:", this->port_);
this->dieWithError("ERROR on binding");
}
printf("-> Binding successful. Start TCP client in new terminal\n");
fflush(stdout);
/* listen for connections and accept a connection */
listen(this->sockfd_, 5);
this->clilen_ = sizeof(this->cli_addr_);
if ((this->newsockfd_ = accept(this->sockfd_, (struct sockaddr *) &this->cli_addr_, &this->clilen_)) < 0)
this->dieWithError("Error on accept");
else {
printf("-> Connection established\n");
this->connected_ = true;
}
}
So once the server detects that the connection is closed, it enters a loop where it tries to reconnect using the following code:
void tcpServer::connect() {
if (this->sockfd_ == -1) {
/* create socket */
if ((this->sockfd_ = socket(AF_INET, SOCK_STREAM, 0)) < 0)
this->dieWithError("ERROR opening Socket");
else
printf("-> Port %d: Socket opened\n", this->port_);
// get rid of "address already in use" error message
int reuse_address = 1;
setsockopt(this->sockfd_, SOL_SOCKET, SO_REUSEADDR, &reuse_address, sizeof(int));
/* listen for connections and accept a connection */
listen(this->sockfd_, 5);
this->clilen_ = sizeof(this->cli_addr_);
if ((this->newsockfd_ = accept(this->sockfd_, (struct sockaddr *) &this->cli_addr_, &this->clilen_)) < 0)
this->dieWithError("Error on accept");
else {
printf("-> Connection established\n");
this->connected_ = true;
}
}
}
Some simple debugging output tells me that in the reconnect-mode, the server gets stuck in the
accept(this->sockfd_, (struct sockaddr *) &this->cli_addr_, &this->clilen_) call. Another observation I made is that the client does not shut down properly (via ctrl-c), i.e., it gets stuck in a loop somewhere and does not properly close the connection.
Since I am a total beginner with the TCP stuff, I would be very happy if someone could point me to the right direction. Thank you.
Where do I set TCP_NODELAY in this C++ TCP Client?
// Client socket descriptor which is just integer number used to access a socket
int sock_descriptor;
struct sockaddr_in serv_addr;
// Structure from netdb.h file used for determining host name from local host's ip address
struct hostent *server;
// Create socket of domain - Internet (IP) address, type - Stream based (TCP) and protocol unspecified
// since it is only useful when underlying stack allows more than one protocol and we are choosing one.
// 0 means choose the default protocol.
sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);
if (sock_descriptor < 0)
printf("Failed creating socket\n");
bzero((char *) &serv_addr, sizeof(serv_addr));
server = gethostbyname(host);
if (server == NULL) {
printf("Failed finding server name\n");
return -1;
}
serv_addr.sin_family = AF_INET;
memcpy((char *) &(serv_addr.sin_addr.s_addr), (char *) (server->h_addr), server->h_length);
// 16 bit port number on which server listens
// The function htons (host to network short) ensures that an integer is
// interpreted correctly (whether little endian or big endian) even if client and
// server have different architectures
serv_addr.sin_port = htons(port);
if (connect(sock_descriptor, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
printf("Failed to connect to server\n");
return -1;
} else
printf("Connected successfully - Please enter string\n");
TCP_NODELAY is option given to setsockopt system call:
#include <netinet/tcp.h>
int yes = 1;
int result = setsockopt(sock,
IPPROTO_TCP,
TCP_NODELAY,
(char *) &yes,
sizeof(int)); // 1 - on, 0 - off
if (result < 0)
// handle the error
This is to set Nagle buffering off. You should turn this option on only if you really know what you are doing.
I'm trying to create a server socket with C++ in order to accept one client connection at a time. The program successfully creates the server socket and waits for incoming connections but when a connection is closed by the client the program would loop endlessly. Otherwise if the connection is interrupted it would keep waiting for new connections as expected. Any idea why this is happening? Thanks
This is my C++ server code:
int listenfd, connfd, n;
struct sockaddr_in servaddr, cliaddr;
socklen_t clilen;
pid_t childpid;
char mesg[1000];
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(32000);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, 1024);
while (true) {
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
if ((childpid = fork()) == 0) {
close (listenfd);
while (true) {
n = recvfrom(connfd, mesg, 1000, 0, (struct sockaddr *)&cliaddr, &clilen);
sendto(connfd, mesg, n, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
mesg[n] = 0;
printf("%d: %s \n", n, mesg);
if (n <= 0) break;
}
close(connfd);
}
}
For some reason when the client closes the connection the program would keep printing -1: even with the if-break clause..
You never close connfd in parent process (when childpid != 0), and you do not properly terminate child process that will try to loop. Your if block should look like :
if ((childpid = fork()) == 0) {
...
close(connfd);
exit(0);
}
else {
close(connfd);
}
But as you say you want to accept one connection at a time, you can simply not fork.
And as seen in other answers :
do not use mesg[n] without testing n >= 0
recvfrom and sendto are overkill for TCP simply use recv and send (or even read and write)
mesg[n] = 0;
This breaks when n<0, ie. socket closed
The problem is your "n" and recvfrom. You are having a TCP client so the recvfrom won't return the correct value.
try to have a look on :
How to send and receive data socket TCP (C/C++)
Edit 1 :
Take note that you do the binding not connect() http://www.beej.us/guide/bgnet/output/html/multipage/recvman.html
means there is an error in recieving data, errno will be set accordingly, please try to check the error flag.
you've written a TCP server, but you use recvfrom and sendto which are specific for connection-less protocols (UDP).
try with recv and send. maybe that might help.