I'm a beginner and trying to set up a TCP-client for the first time, using winsock. I put together a minimal client using some bits of code I found in examples (see below). It's basically working, i.e. I can receive the server's messages, and sending messages gives the expected results.
However, unless I add a loop which constantly does a receive/send routine (or even just the receive part) the connection is closed immediately after it has been established. Can I do something to keep the connection open and only receive or send something when there is demand for it?
The server is a closed source piece of software, so I have no idea about how it is set up.
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
int startWinsock(void) {
WSADATA wsa;
return WSAStartup(MAKEWORD(2, 2), &wsa);
}
int main(void) {
long rc;
SOCKET s;
SOCKADDR_IN addr;
printf("Starting Winsock... ");
rc = startWinsock();
if (rc != 0) {
printf("Error: unable to start Winsock, error code: %d\n", rc);
}
else {
printf("done.\n");
}
printf("Creating socket... ");
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
printf("Error: Unable to create socket, error code: %d\n", WSAGetLastError());
}
else {
printf("done.\n");
}
memset(&addr, 0, sizeof(SOCKADDR_IN));
addr.sin_family = AF_INET;
addr.sin_port = htons(10134);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
rc = connect(s, (SOCKADDR*)&addr, sizeof(SOCKADDR));
if (rc == SOCKET_ERROR) {
printf("Connection failed, error code: %d\n", WSAGetLastError());
}
else {
printf("Connected to 127.0.0.1.\n");
}
//if I add a loop here, which receives and/or sends stuff constantly, the connection stays established
return 0;
}
Very simple:
Your client tries to connect to the server.
If it succeeds, send a command, and read the response.
Keep receiving and sending until you're "done", then close the socket.
In other words:
You have control over when to close the connection - the socket will stay open until you close it.
Essentially, you're inventing your own custom network protocol
STRONG SUGGESTION:
Review Beej's Guide to Network Programming
Related
I am writing a program which is supposed to act as a simple proxy between a web server and a browser. The browser connects to my proxy program and my program connects to the web server. My proxy program should simply forward all data it receives from the browser to the web server and vice-versa, without modifying the data in any way and without performing any caching.
I have managed to get a reply from a web server but how would I direct that reply to my browser? Also is there any way to put this into some sort of infinite loop where I can recv and send at will?
Edit:
I've almost got it. I just need to know how to continuously read the sockets. The program closes unexpectedly after I get the Http redirect.
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#define SERVER_PORT 8080
#define SA struct sockaddr
#define MAX 80
pthread_t ptid, ptidd;
#define TRUE 1
#define FALSE 0
struct sockets_struct {
int server_sd;
int client_sd;
int new_sd;
}socks;
// Function designed to act as client.
void *client_func(void *sockets)
{
char buffer[MAX];
struct sockaddr_in servaddrr;
struct sockets_struct *socks = (struct sockets_struct*)sockets;
int i, len, rc, on = 1;
//bzero(&servaddrr, sizeof(servaddrr));
// assign IP, PORT
servaddrr.sin_family = AF_INET;
servaddrr.sin_addr.s_addr = inet_addr("192.168.0.1");
servaddrr.sin_port = htons(80);
// connect the client socket to server socket
if (connect(socks->client_sd, (SA*)&servaddrr, sizeof(servaddrr)) != 0) {
printf(" client: connection with the server failed...\n");
exit(0);
}
else
printf(" client: connected to the remote server..\n");
do {
rc = recv(socks->client_sd, buffer, sizeof(buffer), 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" client: recv() failed\n");
}
break;
}
if (rc == 0) {
printf(" client: Connection closed\n");
break;
}
len = rc;
printf(" client: %d bytes received\n", len);
rc = send(socks->new_sd, buffer, len, 0);
if (rc < 0) {
perror(" client: send() failed");
break;
}
} while(TRUE);
}
// Function designed to act as server.
void *server_func(void *sockets)
{
int len, rc, on = 1;
int desc_ready, end_server = FALSE, compress_array = FALSE;
int close_conn;
char buffer[80];
struct sockaddr_in6 addr;
int timeout;
struct pollfd fds[200];
int nfds = 1, current_size = 0, i, j;
struct sockets_struct *socks = (struct sockets_struct*)sockets;
rc = setsockopt(socks->server_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (rc < 0) {
perror(" server: setsockopt() failed\n");
close(socks->server_sd);
exit(-1);
}
rc = ioctl(socks->server_sd, FIONBIO, (char *)&on);
if (rc < 0) {
perror(" server: ioctl() failed\n");
close(socks->server_sd);
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET;
memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
addr.sin6_port = htons(SERVER_PORT);
rc = bind(socks->server_sd, (struct sockaddr *)&addr, sizeof(addr));
if (rc < 0) {
perror(" server: bind() failed");
close(socks->server_sd);
exit(-1);
}
rc = listen(socks->server_sd, 32);
if (rc < 0) {
perror(" server: listen() failed");
close(socks->server_sd);
exit(-1);
}
memset(fds, 0 , sizeof(fds));
fds[0].fd = socks->server_sd;
fds[0].events = POLLIN;
timeout = (3 * 60 * 1000);
do {
printf(" server: waiting on poll()...\n");
rc = poll(fds, nfds, timeout);
if (rc < 0) {
perror(" server: poll() failed\n");
break;
}
if (rc == 0) {
printf(" server: poll() timed out. End program.\n");
break;
}
current_size = nfds;
for (i = 0; i < current_size; i++) {
if (fds[i].revents == 0)
continue;
if (fds[i].revents != POLLIN) {
printf(" server: Error! revents = %d\n", fds[i].revents);
end_server = TRUE;
break;
}
if (fds[i].fd == socks->server_sd) {
printf(" server: Listening socket is readable\n");
socks->new_sd = accept(socks->server_sd, NULL, NULL);
if (socks->new_sd < 0) {
if (errno != EWOULDBLOCK) {
perror(" server: accept() failed\n");
end_server = TRUE;
}
break;
}
printf(" server: new incoming connection - %d\n", socks->new_sd);
fds[nfds].fd = socks->new_sd;
fds[nfds].events = POLLIN;
nfds++;
}
else {
printf(" server: Descriptor %d is readable\n", fds[i].fd);
close_conn = FALSE;
do {
rc = recv(fds[i].fd, buffer, sizeof(buffer), 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
close_conn = TRUE;
}
break;
}
if (rc == 0) {
printf(" server: Connection closed\n");
close_conn = TRUE;
break;
}
len = rc;
printf(" server: %d bytes received \n", len);
rc = send(socks->client_sd, buffer, len, 0);
if (rc < 0) {
perror(" server: send() failed\n");
close_conn = TRUE;
break;
}
} while(TRUE);
if (close_conn) {
close(fds[i].fd);
fds[i].fd = -1;
compress_array = TRUE;
}
} /* End of existing connection is readable */
} /* End of loop through pollable descriptors */
} while (end_server == FALSE); /* End of serving running. */
}
int main (int argc, char *argv[])
{
socks.server_sd = socket(AF_INET, SOCK_STREAM, 0);
socks.client_sd = socket(AF_INET, SOCK_STREAM, 0);
if (socks.server_sd == -1) {
printf("socket \"server_sd\" creation failed...\n");
exit(0);
}
else
printf("Socket \"server_sd\" successfully created..\n");
if (socks.client_sd == -1) {
printf("socket \"client_sd\" creation failed...\n");
exit(0);
}
else
printf("Socket \"client_sd\" successfully created..\n");
pthread_create(&ptidd, NULL, &client_func, &socks);
pthread_create(&ptid, NULL, &server_func, &socks);
pthread_join(ptidd, NULL);
return 0;
}
You can either write a proxy that understands the data it's proxying or one that doesn't. Your question suggests that you want to write one that doesn't. That is definitely the easier approach.
So once all the connections are setup, you have two things to do. You need to read data from one connection and send it to the other. You also need to read data from the other connection and send it to the first one.
Using two threads is an easy way to do this. You can also fork a process for each direction. But the first way that everyone learns is a select or poll loop. You can punch "select loop proxy" into your favorite search engine to find lots of examples.
NOTE: This answer was written at a time before the OP edited the question and added threads to the code in the question.
The main problem I see with your algorithm is that you seem to assume that you will always receive all data from the client and server in one recv or read call. This cannot be relied upon, even if the web client (browser) only sends a single HTTP request (which is very unlikely, even if only one web page gets loaded).
I suggest you use the following algorithm instead:
Wait for web client (browser) to establish connection to your program.
Create a new socket which connects to web server.
Wait for web server connection to be established. This step is not necessary with your program, as you are using a blocking connect call. It is only necessary if non-blocking or asynchronous sockets are used.
Wait for new data to be available to be read on either of the two sockets, for example by using the function select. When this function returns, it will indicate on which sockets a non-blocking call to recv is possible.
Read from the socket(s) that select reports as having data available to be read, and write this data to the other socket using the send function.
Go to step 4.
However, this algorithm has one possible problem: It assumes that send will always be successful at writing all the bytes immediately, without blocking. Depending on the circumstances (for example the operating system's buffering of sockets) this may not always be the case. It may only be able to partially send the contents of the buffer at once. The documentation of the function send does not specify what will happen if the buffer of the send function is too large to be sent at once, i.e. whether it will block until all the data is sent or whether it will return as soon as it was able to perform a partial send.
Therefore, your algorithm should be able to deal with the case that the data is only partially sent, for example by also checking in step 4 whether it is possible to write more data if not all data was written in a previous call to send.
Also, beware that while your program is blocking on a send call, it will not process any communication in the other direction. For example, while your program is blocking on a send call while forwarding data from the client to the server, it will be unable to forward any data from the server to the client. I don't think that this can cause trouble with the HTTP protocol, because the client and server never send data simultaneously, as the server always waits for the client to finish its request and the client then waits for the server to finish its reply, before it sends another request. However, this may be an issue with other protocols. In particular, if you block communication completely in one direction, this may cause the client or server to get stuck on a blocking send or recv call, too. This could cause a deadlock in all three programs.
Therefore, you may want to consider using non-blocking sockets or asynchronous sockets instead, so that you can continue forwarding network traffic in both directions at all times.
Alternatively, you could continue using blocking socket calls and create two threads, one for forwarding data from the client to the server and one for forwarding data from the server to the client. That way, communication will never be blocked in any direction. But I would recommend using non-blocking sockets or asynchronous socket instead, as threads can get messy.
One thing your algorithm should also do is handle an orderly socket shutdown (indicated by recv returning 0) and error conditions. How to do this depends on what kind of sockets you are using, i.e. whether they are blocking, non-blocking or asynchronous.
I want to learn how to write a concurrent TCP client server in C but I can't understand the diffrence between an iterative server-client programm and a concurrent one. On the internet I could not find much information. I look over the TCP client server implementation in C from the site www.geeksforgeeks.org but I think this is an iterative example. How could I make it concurrent?
TCP Server:
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
// Function designed for chat between client and server.
void func(int sockfd)
{
char buff[MAX];
int n;
// infinite loop for chat
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
read(sockfd, buff, sizeof(buff));
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
n = 0;
// copy server message in the buffer
while ((buff[n++] = getchar()) != '\n')
;
// and send that buffer to client
write(sockfd, buff, sizeof(buff));
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
}
}
// Driver function
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
len = sizeof(cli);
// Accept the data packet from client and verification
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client...\n");
// Function for chatting between client and server
func(connfd);
// After chatting close the socket
close(sockfd);
}
TCP Client:
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr
void func(int sockfd)
{
char buff[MAX];
int n;
for (;;) {
bzero(buff, sizeof(buff));
printf("Enter the string : ");
n = 0;
while ((buff[n++] = getchar()) != '\n')
;
write(sockfd, buff, sizeof(buff));
bzero(buff, sizeof(buff));
read(sockfd, buff, sizeof(buff));
printf("From Server : %s", buff);
if ((strncmp(buff, "exit", 4)) == 0) {
printf("Client Exit...\n");
break;
}
}
}
int main()
{
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(PORT);
// connect the client socket to server socket
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
printf("connection with the server failed...\n");
exit(0);
}
else
printf("connected to the server..\n");
// function for chat
func(sockfd);
// close the socket
close(sockfd);
}
As stated in the comments, an iterative server will treat each connection sequentially. In your posted example, if you run the server(after ignoring a bunch of warnings), you can only connect one client. A second client will successfully connect the server, but the server will never respond to it. Only the first client will send messages and get responses.
A concurrent implementation would treat both clients in parallel and would be able to get messages from both. I can think of 3 ways to do this, but one is not recommended:
As suggested in the comments, put the accept call in a loop. It will block until someone connects. When someone connects, you spawn a thread and give it all the information you need to communicate with the client, the file descriptor(sockfd) should suffice for a simple example. After that the thread could execute your func, for this thread will only know of one client, but the main loop will block of accept again, waiting for another connection. I found this example on google.
Using POSIX system call select(or it's alternatives poll and epoll), you can monitor a list of sockets for activity. If any of the monitored sockets has activity, a read or accept to it won`t block, and then you treat these sockets. If the server file descriptor has activity, it means a new client connected, you should store the client file descriptor somewhere, and start passing it to select as well. If a client file descriptor has activity, you handle their messages like before. This way requires no thread, everything is handled on the main routine and may have advantages depending on your use-case
I found these two examples on google: here and here
This way is not recommended: Make your server socket non-blocking with fcntl. This way, accept won't block, instead, it will immediately return signaling an error EAGAIN or EWOULDBLOCK. You can then repeatedly call accept on your main loop, most times it will return an error, but the ones that do not will signal a new client connected. When a client connects, you make its file descriptor non-blocking as well, and store it somewhere. On your main routine, for each client socket you will try a read on them, but if no new information is available, it returns an error as well. If something is available, you treat it like before. This has the disadvantage of always demanding 100% CPU utilization. You can insert a delay on the loop, but it will increase additional unnecessary latency. You should not do this.
I am writing a C software to interface with a motorcontroller over UDP.
I'm using:
Win 7 Pro 64-Bit
eclipse luna
minGW
At the moment I have a problem, that seems to be socket/wsa related:
the execution of my program gets stuck on the recvfrom() forever (so obviously the controller doesn't respond as expected).
With the attached software this only happens on the first execution (or after not executing for ca. 3 mins) other programs had this problem 3-4 times in a row.
A look into wireshark revealed, that the first (or after 3min pause) leads to the transmission of an "ARP" package instead of my UDP message.
Why is that (it seems to be searching for the destination)? How can I avoid "crashing" my software due to this?
Did I forget to initialise anything?
My code looks like this:
#include <stdio.h>
#include <conio.h>
#include <winsock2.h>
#define Y_AXIS_IP "XXX.XXX.XXX.XX"
#define Y_AXIS_PORT 880X
int startWinsock(void);
int main() {
//Start the winsocket (needed to create sockets)
long ws = startWinsock();
if (ws) {
printf("ERROR: Failed to init Winsock API! Code: %ld\n", ws);
getch();
exit(EXIT_FAILURE);
}
//Create an UDP Socket
SOCKET UDPsocket = socket(AF_INET, SOCK_DGRAM, 0);
if (UDPsocket == INVALID_SOCKET) {
printf("ERROR: Socket could not be created! Code: %d\n",
WSAGetLastError());
getch();
exit(EXIT_FAILURE);
}
//Create a struct to use with the socket (this gives information about type (AF_INET = Internet Protocol) which port and which IP to use)
SOCKADDR_IN addrY;
memset(&addrY, 0, sizeof(addrY));
addrY.sin_family = AF_INET; //Assert Type
addrY.sin_port = htons(Y_AXIS_PORT); //Assert Port
addrY.sin_addr.S_un.S_addr = inet_addr(Y_AXIS_IP); //assert IP Address
char message[] = "0000MTX 00000000OR:1:000F\r";
int buffersize = 100;
char *recvbuf = malloc(buffersize); //None of the replys can get larger than 100 chars
if (recvbuf == NULL) {
printf("Out of memory!\n");
getch();
exit(EXIT_FAILURE);
}
//clear the receive buffer and prepare the address size
memset(recvbuf, '\0', buffersize);
int addrsize = sizeof(addrY);
//Send the message to the device
if (sendto(UDPsocket, message, strlen(message), 0,
(struct sockaddr *) &addrY, sizeof(addrY)) == SOCKET_ERROR) {
printf("sendto() failed with error code : %d", WSAGetLastError());
getch();
exit(EXIT_FAILURE);
}
//Receive from device (blocks program until recv event)
if (recvfrom(UDPsocket, recvbuf, buffersize, 0, (struct sockaddr *) &addrY,
&addrsize) == SOCKET_ERROR) {
//If not timed out Display the Error
printf("recvfrom() failed with error code : %d", WSAGetLastError());
getch();
exit(EXIT_FAILURE);
}
printf("%s\n", recvbuf);
getch();
free(recvbuf);
return 0;
}
int startWinsock(void) {
WSADATA wsa;
return WSAStartup(MAKEWORD(2, 2), &wsa);
}
I would be really happy, if you had any ideas or suggestions. Thanks alot in advance!
Before a computer can send a packet to another host, it has to resolve its MAC address. This is done via an ARP request. It is handled by the operating system transparently.
recvfrom will block. It is not a bug. There are basically three ways of avoiding recvfrom from blocking forever when there is no incomming data:
make the socket asynchronous, i.e. nonblocking
set a timeout (see Set timeout for winsock recvfrom)
use select (Setting winsock select timeout accurately)
So finally I found a way to deal with this issue:
1. catch the timeout that occurs at recvfrom
2. save the sockets address in a temporary socket
3. close the original socket
4. end the WSA (call WSACleanup())
5. start the WSA (call WSAStartup())
6. create a new socket at the address of the former socket
7. transmit the message again
seems to work fine (also see code below)
If you see anything wrong or dangerous with my code, please feel free to comment and help my to improve my skills.
Thank you for your help and ideas,
Sebastian
Code:
if (recvfrom(*UDPsocket, buffer, buffersize, 0, (struct sockaddr *) &addr,
&addrsize) == SOCKET_ERROR) {
int WSAerror = WSAGetLastError();
if (WSAerror == 10060) {
printf("[WARNING] recvfrom() timed out!\n");
//Store the address of the socket
SOCKET *tempsocket = NULL;
tempsocket = UDPsocket;
//destroy the old socket
closesocket(*UDPsocket);
WSACleanup();
//create a new socket
startWinsock();
*tempsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//Send the message to the device
if (sendto(*tempsocket, Frame.pcompletemsg,
strlen(Frame.pcompletemsg), 0, (struct sockaddr *) &addr,
sizeof(addr)) == SOCKET_ERROR) {
printf("[ERROR] sendto() failed with error code : %d\n",
WSAGetLastError());
getch();
WSACleanup();
exit(EXIT_FAILURE);
}
if (recvfrom(*tempsocket, buffer, buffersize, 0,
(struct sockaddr *) &addr, &addrsize) == SOCKET_ERROR) {
int WSAerror = WSAGetLastError();
printf("[ERROR] recvfrom() failed with error code : %d",
WSAerror);
getch();
WSACleanup();
exit(EXIT_FAILURE);
}
} else {
printf("[ERROR] recvfrom() failed with error code : %d", WSAerror);
getch();
WSACleanup();
exit(EXIT_FAILURE);
}
}
I have a problem with a client/server programm on linux.
I wrote a server programm wich is sending data cyclic to one conneted client.
Now I want to detect, if the client close the connection to the server. When the connection is closed from the client, i want to wait with accept(...) for an new connection.
Here the critical parts of my code:
error = send(client_sock, Zeichen, 1, MSG_NOSIGNAL);
if(error < 0)
{
connected = 0;
printf("Error, write on TCP Socket failed!!! Reconnecting... \r\n");
close(serverSocket);
initServer();
}
int initServer(void)
{
int *new_sock;
socklen_t size;
struct sockaddr_in server, client;
serverSocket = socket(AF_INET , SOCK_STREAM , 0); //Create socket
if (serverSocket == -1)
{
printf("Could not create socket \r\n");
return 0;
}else
{
printf("Socket created \r\n");
}
server.sin_addr.s_addr = inet_addr(IPAdresse);
server.sin_family = AF_INET;
server.sin_port = htons(TCPPort);
if(bind(serverSocket,(struct sockaddr *)&server , sizeof(server)) < 0)
{
printf("bind failed. Error \r\n");
return 0;
}else
{
printf("bind done \r\n");
}
listen(serverSocket, 1);
printf("Waiting for incoming connections... \r\n");
size = sizeof(sockaddr_in);
printf("size of sockaddr_in: %i \r\n", size);
client_sock = accept(serverSocket, (struct sockaddr *)&client, &size);
if (client_sock < 0)
{
printf("accept failed \r\n");
return 0;
}else
{
connected = 1;
return 1;
}
}
The first time it works fine, I can connect and can send data over the socket. When the client close the connection the error is detected, I close the socket an start the server again to wait for a new connection. But than I get a segmentation fault when I do the accept(..) for the second time!!!
Can someone help me please!!! Thanks a lot!
It's not clear what you're doing when the client connection closes. I see no loop in your code, and yet you're suggesting that accept() is called more than once.
Without seeing the rest or the code, I can only speculate that:
you're repeatedly calling initServer(), hence attempting to recreate the same server socket over and over (which, of course, would be bad),
or
you're calling accept() again somewhere else in your code, most likely with corrupt arguments.
At the very least, what your server-side code should do is initialize the server socket once, then loop around accept(), like so:
call socket() once
call bind() once
call listen() once
then in a loop:
call accept(), this call will block until a client connects, and then return a connected socket,
do whatever you need to do with that (connected client) socket
resume with the loop
RFC 793 says that TCP defines a "push" function that ensures that the receiver got the data:
Sometimes users need to be sure that all the data they have
submitted to the TCP has been transmitted. For this purpose a push
function is defined. To assure that data submitted to a TCP is
actually transmitted the sending user indicates that it should be
pushed through to the receiving user. A push causes the TCPs to
promptly forward and deliver data up to that point to the receiver.
However, I can't find a push system call. Using fsync on the file descriptor produces an invalid argument error.
I conducted an experiment with a simple server that accepts a connection from a client, waits, then sends 26 bytes to the client:
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 1234
int main(void)
{
int server_fd;
int client_fd;
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return 1;
}
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
perror("bind");
return 1;
}
}
if (listen(server_fd, 20) != 0) {
perror("listen");
return 1;
}
{
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
printf("Waiting for connection on port %d\n", PORT);
if ((client_fd = accept(server_fd, (struct sockaddr*)&addr, &addrlen)) < 0) {
perror("accept");
return 1;
}
printf("%s:%d connected\n",
inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port));
}
printf("Giving client time to close connection.\n");
sleep(10);
{
ssize_t sent_length;
if ((sent_length =
send(client_fd, "abcdefghijklmnopqrstuvwxyz", 26, 0)) < 0)
{
perror("send");
return 1;
}
printf("Sent %Zd bytes.\n", sent_length);
}
printf("Closing connection to client\n");
if (close(client_fd) != 0) {
perror("close(client_fd)");
return 1;
}
printf("Shutting down\n");
if (close(server_fd) != 0) {
perror("server: close(server_fd)");
return 1;
}
printf("Done!\n");
return 0;
}
I found that the send call immediately returns 26, even after I close the connection client-side or unplug the network cable. In the latter case, the data appears on the client when I plug the cable back in and wait a few seconds (long after the server has shut down).
How do I ensure that data sent with send is received and acknowledged?
There is no push, says the late W. Richard Stevens; the standard sockets API doesn't provide it, and is not required to do so by RFC 1122. You can set the TCP_NODELAY option, but that's only a partial solution.
If you want to be sure the other end got your data, then let it send an acknowledgment over the TCP channel.
try to add a shutdown call before the close of the socket;
shutdown(client_fd,SHUT_RDWR);
However the real solution is to get an acknowledgement back from the client that it has received the data -- I.e. you need to define a protocol -- the simplest of simple protocols is that the client is responsible for closing the socket when the data is received.
Well as per my limited knowledge, TCP will insure that the data is transferred to the other machine / socket.
But has the program at the other end read / accessed the data cannot be confirmed using standard socket API's. Your other end (client in this case) might be busy doing something else instead of waiting for data to show up.
I think that your requirement will be full filled if you implement some sort of handshaking between server / client to track what all has been received using some kind of acknowledgements.
The acknowledgement mechanism is important if your application depends on it.
You can force immediately sending of small packets by disabling Nagle's algorithm, but this does not guarantee that the client will receive it.
If you have to wait for the acknowledge you have to build this into the protocol and wait for the client to write something into the socket that signals the reception of message.
The only way to make sure your data is send over is to Receive an answer. After testing for many days this is the only way to make sure it is 'flushed' to the other side.
// Receive until the peer closes the connection to make sure all data has been send
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0){
printf("Bytes received: %d\n", iResult);
}
else if (iResult == 0){
printf("Connection closed\n");
}
else{
printf("recv failed with error: %d\n", WSAGetLastError());
}
} while (iResult > 0);