I tried to learn about the conception of Socket-Send(Receive)-Buffer.And I wrote these codes:
Client:
int client = socket(AF_INET, SOCK_STREAM, 0);
int s = getsockopt(client, SOL_SOCKET, SO_SNDBUF, &sendBuffSize, &len);
int status = connect(client, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
printf("The send buff size is : %d.\n", sendBuffSize);
char buf[100000];
int n, wn;
int fd = open("./1.txt", O_RDONLY);
while ((n = read(fd, buf, sizeof(buf))) > 0) {
wn = write(client, buf, n);
printf("Write %d bytes.\n", wn);
}
Server: I set the connected client as Non-block,and add this client into the epoll.Once the client sends data to the server, I put the main thread into sleep[ten seconds].
char buf[8192];
sleep(10);
int rn;
while ((rn = read(events[i].data.fd, buf, sizeof(buf))) > 0) {
printf("Read %d bytes.\n", rn);
}
The client send Buffer size is 16384 and the server receive Buffer size is 20000[setsockopt].
According to the book:The client calls the write function will block if the socket send buffer is full.
But I get the result[Client] :
Result
And the server :
Result
Questions:
Receive buffer size + Send buffer size < 100000; but why the write function do not block?
Why the server read 8192 + 6808 = 15000 bytes instead of read continuously 8192 bytes?
There is no evidence here that the client writes did not block. On the contrary, the fact that all the writes were 100,000 bytes except the last, when you ran out of input, shows that it must have blocked, to transfer all that data into a socket buffer that is smaller.
TCP segmentizes, and IP packetises, the data sent over the wire. You have no control over that process. In any case a read() can transfer any amount of bytes from 1 up to the count supplied, or zero upwards in non-blocking mode. It is a streaming protocol, not a messaging protocol. There is no other guarantee about how much any individual read() will return at a time.
Related
I want to send data from a client written in Matlab to a server written in C. When reading in the server, not all data is received in one read action and it is divided into two consecutive reads.
The Matlab code contains the code for a TCP server that receives some data, then does some processing and then writes (sends) the output of the processing over a TCP socket as a client to the server in C.
Here is the code for the client written in Matlab.
% A TCP server object defined for getting raw data and processing
% it. The object is called 'TCPServer'. It is not related to the
% problem.
% TCP client for sending the data to the C server
TCPClient = tcpip('192.168.1.2', 8080, 'NetworkRole', 'client');
set(TCPClient,'OutputBufferSize', 1464);
% 1464 is total number of bytes of the struct to be sent
% to the C server.
set(TCPClient,'Timeout', 10);
fopen(TCPClient);
while (1)
while(1) % Waits for incoming CSI data
nBytes = get(TCPServer,'BytesAvailable');
if nBytes >= bufferLen
disp('Data received');
break;
end
end
data = fread(TCPServer,nBytes,'uint8');
flushinput(TCPServer);
% Does some processing and generate 'spec' and 'doas'
% arrays to be sent to the C server
message = [typecast(spec, 'uint8') typecast(doas, 'uint8')];
fwrite(TCPClient, message);
end
Here is the code written in C for the server receiving the data from the client in Matlab.
#define SA struct sockaddr
struct doa_struct {
double spec[181], doa[2];
};
// Function that reads received data
void func(int sockfd)
{
struct doa_struct *doa_data;
unsigned char buff[1464];
int num_bytes;
// infinite loop receiving data
for (;;) {
bzero(buff, 1464);
// read the data from client and copy it in buffer
num_bytes = read(sockfd, buff, 1464);
// Get the buffer which contains the client contents
doa_data = (struct doa_struct *) buff;
printf("doa: %f\t%f\t%d\n", doa_data->doa[0], doa_data->doa[1], num_bytes);
}
}
// 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(8080);
// 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);
}
I receive the following result on the server.
doa: 0.000000 0.000000 1408
doa: 0.000000 0.000000 56
Each line printed has three values. The first two are the received data that should not be zero. The last number is the number of bytes received by read() function in the server. The sum of bytes received by the server in the two lines (two read() operations) is 1464 which is the number of bytes sent by the client in one fwrite() operation.
The correct output would be one line like the following:
doa: 25.000000 45.000000 1464
Two non-zero data values received by a transfer of 1464 bytes. I have also checked the client code. The client sends (writes) 1464 bytes by fwrite() operation in Matlab.
It's completely normal for a read() call to only return some of the data you're expecting. This happens because at a low level, the network stack breaks the overall data stream up into multiple fixed-size packets for transmission over the wire. From the read(2) man page:
RETURN VALUE ... It is not an error if this number is smaller than the number of bytes requested; this
may happen for example because fewer bytes are actually available right now (maybe
because we were close to end-of-file, or because we are reading from a pipe, or from a
terminal), or because read() was interrupted by a signal.
When receiving network data, you'll need to keep calling read() until you've received the expected number of bytes. For example, something like this (untested code):
void func(int sockfd)
{
struct doa_struct *doa_data;
int expected_bytes = 1464;
unsigned char buff[expected_bytes];
int num_bytes;
// Read a message
bzero(buff, 1464);
int bytes_read = 0;
while (bytes_read < expected_bytes) {
// read data into buff until we've read all the expected bytes
// NOTE: if the Matlab side sends a malformed message, this could
// hang in this loop forever...for real-world use, you'd need to
// account for those types of scenarios.
num_bytes = read(sockfd, buff + bytes_read, expected_bytes - bytes_read);
if (num_bytes <= 0) {
// handle error cases...
return;
}
bytes_read += num_bytes;
}
// Get the buffer which contains the client contents
doa_data = (struct doa_struct *) buff;
printf("doa: %f\t%f\t%d\n", doa_data->doa[0], doa_data->doa[1], num_bytes);
}
As for why your output is printing 0's instead of the expected values: it may be because of your printf format specifier. Your compiler may require "%lf" to print doubles, rather than "%f". Traditionally, the "%lf" was required for doubles, which are 64-bit values rather than the 32-bit float values. However, C99 and later compilers can blur this line -- see this related stack overflow question.
I am trying to understand why my function dosnt sending the all string (Its send only 53576 elements from 365568:
This is the function I am using in the client side:
#define DATASIZEBUFFER 4000// 365568
void DieWithError(char *errorMessage);/* Error handling function */
void TcpClient ( char *servIP , unsigned short echoServPort , Hash_t *HashData)//(int argc, char *argv[])
{
int sock; //Socket descriptor
struct sockaddr_in ServAddr; //Echo server address
int bytesRcvd, totalBytesRcvd; //Bytes read in single recv()
//and total bytes read
// Create a reliable, stream socket using TCP
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithError(" socket () failed") ;
// Construct the server address structure
memset(&ServAddr, 0, sizeof(ServAddr)); /* Zero out structure */
ServAddr.sin_family = AF_INET; /* Internet address family */
ServAddr.sin_addr.s_addr = inet_addr(servIP);/* Server IP address */
ServAddr.sin_port = htons(echoServPort); /* Server port */
// Establish the connection to the server
if (connect(sock, (struct sockaddr *) &ServAddr, sizeof(ServAddr)) < 0)
DieWithError(" connect () failed") ;
for (;;)
{
// Send the string to the server //
if (send(sock, HashData->array , HashData->elementNumber, 0) != HashData->elementNumber)
{
printf ("Bytes Nedded to recived: %ld\nAnd (DATASIZEBUFFER) is %d\n", HashData->elementNumber , DATASIZEBUFFER);
DieWithError("send() sent a different number of bytes than expected");
}
}
send() does not guarantee that it would send all the data.
From send man page:
On success, these calls return the number of bytes sent. On error,
-1 is returned, and errno is set appropriately.
You can write a loop around send() and invoke it multiple times until all data is sent (or, error is returned). It could be something like the following (please modify it based on your needs):
size_t
Send(int sockfd, const void *buf, size_t len, int flag) {
size_t sent_total = 0;
for (int sent_now = 0; sent_total != len; sent_total += sent_now) {
sent_now = send(sockfd, buf + sent_total, len - sent_total, flag);
if (sent_now == -1) break;
}
if (sent_total != len) {
LOG("send requested = %zu, sent = %zu", len, sent_total);
}
return sent_total;
}
Update to address #Myst's comments:
Although the question did not mention it explicitly, I assumed that the sockets used are blocking, since there are no fcntl call. With that in mind, the following from send() man page explains the situation:
When the message does not fit into the send buffer of the socket,
send() normally blocks, unless the socket has been placed in
nonblocking I/O mode.
In nonblocking mode it would fail with the
error EAGAIN or EWOULDBLOCK in this case. The select(2) call may be
used to determine when it is possible to send more data.
For non-blocking socket, the design need to be different and is outside the scope of this discussion.
I have a client and a server. I have two read() in my client and two write() in my server code. The server sends data to the client on the first write(), the client reads and stores to a buffer but it doesn't stop reading, it keeps reading through the server's second write() because in my client i have it set up to read 255 in the stream(from my understanding). I put 255 because i don't know how long the data datasize for first write() is. How do i fix this?
Client:
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
Server:
n = write(newsockfd,datasize,strlen(datasize));
if (n < 0) error("ERROR writing to socket");
n = write(newsockfd,data,255);
if (n < 0) error("ERROR writing to socket");
What you are experiencing is how TCP works. If the server calls write() multiple times before the client calls read(), then read() can receive everything that was previously written, up to the maximum buffer size that you specify. TCP has no concept of message boundaries, like UDP does. There is nothing wrong with that. You just need to account for it, that's all.
If you need to know where one message ends and the next begins, then you simply need to frame your messages. There are a couple of different ways you can do that.
Send the data length before sending the actual data, so the client knows how much data to read, eg:
Server:
int datalen = ...; // # of bytes in data
int tmp = htonl(datalen);
n = write(newsockfd, (char*)&tmp, sizeof(tmp));
if (n < 0) error("ERROR writing to socket");
n = write(newsockfd, data, datalen);
if (n < 0) error("ERROR writing to socket");
Client:
int buflen;
n = read(sockfd, (char*)&buflen, sizeof(buflen));
if (n < 0) error("ERROR reading from socket");
buflen = ntohl(buflen);
n = read(sockfd, buffer, buflen);
if (n < 0) error("ERROR reading from socket");
else printf("%*.*s\n", n, n, buffer);
wrap the data with delimiters that do not appear in the actual data, then the client can keep reading and look for those delimiters. Use whatever delimiters make sense for your data (STX/ETX, line breaks, special reserved characters, etc):
Server:
char delim = '\x2';
n = write(newsockfd, &delim, 1);
if (n < 0) error("ERROR writing to socket");
n = write(newsockfd, data, datalen);
if (n < 0) error("ERROR writing to socket");
delim = '\x3';
n = write(newsockfd, &delim, 1);
if (n < 0) error("ERROR writing to socket");
Client:
char tmp;
do
{
n = read(sockfd, &tmp, 1);
if (n < 0) error("ERROR reading from socket");
if (tmp != '\x2')
continue;
buflen = 0;
do
{
n = read(sockfd, &tmp, 1);
if (n < 0) error("ERROR reading from socket");
if (tmp == '\x3')
break;
// TODO: if the buffer's capacity has been reached, either reallocate the buffer with a larger size, or fail the operation...
buffer[buflen] = tmp;
++buflen;
}
while (1);
printf("%*.*s\n", buflen, buflen, buffer);
break;
}
while (1);
You can't assume that one read will read exactly what was written by one write. TCP is a byte stream protocol. No message boundaries. read() can read as little as one byte and as much as the length you provide, depending on what data has arrived, which you can't control at either the sending or the receiving end. You also can't control whether TCP coalesces outgoing writes into one segment.
If you want messages, you have to implement them yourself, e.g. lines, length-word prefix, type-length-value, STX/ETX, XML, ...
NB When you get an error, don't just print a message of your own devising. Print the error. In this case, call 'perror()', or make up a formatted string with 'strerror'.
You've got the right idea about sending the length data before sending the actual data, but you're sending datasize in the wrong format. Sending it as an ascii string means the length of datasize will vary depending on the length of data:
For instance:
If data is 5 bytes in length, datasize will be "5".
If data is 100 bytes in length, datasize will be "100".
Unfortunately when it comes to serializing data, this just won't work, datasize must always take up the same number of bytes. You need to write this into the socket as an integer, and read it again at the other end as an integer. Then write this exact number of bytes of data into the socket and read this exact number of bytes of data at the other end:
For example:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
void send(int sock)
{
const char* msg = "this is a message!";
uint16_t len = strlen(msg);
uint16_t networkLen = htons(len); // convert to network byte order
write(sock, &networkLen, sizeof(networkLen));
write(sock, msg, len);
}
void receive(int sock)
{
char msg[1024];
uint16_t networkLen;
read(sock, &networkLen, sizeof(networkLen));
uint16_t len = ntohs(networkLen); // convert back to host byte order
read(sock, msg, sizeof(msg) - 1);
msg[len] = '\0';
printf("%u %s\n", len, msg);
}
int main(int argc, char** argv)
{
int sockets[2];
pipe(sockets);
send(sockets[1]);
receive(sockets[0]);
}
Socket == stream of bytes, it doesn't make some packetizing etc. So if Server should send 2 packets to client, you need to do something so client can distinguish each of them. For instance, if you decide that server should send 2 packets by 255 bytes each, your client procedure which receives one packet would look like this:
int count = 0;
while (count < 255) {
n = read(sockfd, buffer + count, 255 - count);
if (n < 0) {
error("ERROR reading from socket");
printf("%s\n",buffer);
return;
}
count += n;
}
// here buffer has 255 bytes for the packet
The program has cycle, because you can receive any number in read result in between 0..255, or negative if the socket was closed.
you can do the same for second packet.
If your packets are different in size, then you have to tell client from server what the packet size is. You can send in first 2 bytes the length of your packet, and use the number instead of 255 constant in code above.
I want to use the sendto() API to send video and audio data through UDP packet. The sending buffer size I got using getsockopt() is 114688, however, sendto() returned -1 when the data packet less than 65536 not 114688. And the error message is Message too long.
When I used setsockopt() to adjust the sending buffer size as 200000, I used getsockopt() and found the sending buffer size was not 200000 but 262142. So I still got the same error when I sent data packet with a size bigger than 65536.
I am confused about this situation. I want to know what the reason is and how to solve this problem.
When I used FFMPEG library to send the video and audio packet, there is no error. So I am sure there is a solution for this problem and I missed something.
Is there anyone can help me about this problem? I really can not understand what the reason is.
The OS I used is ubuntu 11.04,I got the same results in ubuntu 11.10.
That is the code I used to create socket and configure the parameter:
unsigned char *output_buffer = (unsigned char*)av_malloc(IO_BUFFER_SIZE);
if (NULL == output_buffer) {
printf("Couldn't allocate input buffer.\n");
return NULL;
}
output_context_data_t *context_data = (output_context_data_t *)malloc(sizeof(output_context_data_t));
if (NULL == context_data) {
printf("Could not allocate output context data.\n");
av_free(output_buffer);
return NULL;
}
context_data->socket = socket(AF_INET, SOCK_DGRAM, 0);
if(context_data->socket < 0) {
printf("socket creating fail!\n");
return NULL;
}
context_data->socket_addr->sin_family = AF_INET;
context_data->socket_addr->sin_port = htons(output_port);
ret = inet_pton(AF_INET, output_ip, &(context_data->socket_addr->sin_addr));
if(0 == ret) {
printf("inet_pton fail!\n");
return NULL;
}
ret = setsockopt(context_data->socket, IPPROTO_IP, IP_MULTICAST_TTL,
&option_ttl, sizeof(int));
if(ret < 0) {
printf("ttl configuration fail!\n");
return NULL;
}
ret = setsockopt(context_data->socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
if(ret < 0) {
printf("resue configuration fail!\n");
return NULL;
}
That is the code to send UDP packet:
int send_size = sendto(context_data->socket, buf, buf_size, 0,
(struct sockaddr *)context_data->socket_addr, sizeof(*context_data->socket_addr)));
//the video or audio data is in buf and its size is buf_size.
That is the code I used to get the sending buffer size:
int bufsize;
int size = sizeof(bufsize);
getsockopt(context_data->socket,SOL_SOCKET, SO_SNDBUF, &bufsize, &size);
That is the code I used to configure the sending buffer size:
tmp = 200000;
ret = setsockopt(context_data->socket, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp));
if(ret < 0) {
printf("sending buffer size configuration fail!\n");
return NULL;
}
You can not send messages (datagrams) larger than 2^16 65536 octets with UDP. The length field of a UDP packet is 16 bits. The buffer sizes you're requesting are not about the size for a packet, but how many octets the OS does buffer incoming and outgoing in total (spread over multiple packets). But a single packet can not get larger.
Per #datenwolf's answer, you simply can't send more than 64k in a single UDP datagram, as that limit is implicit in the two-byte length field in the protocol.
Furthermore, it's not actually a good idea to send even that much at once. You should limit your packets to the MTU on the path between the two ends (typically in the region of 1500 bytes or less) so that you don't get fragmentation in the IP layer.
Fragmentation is bad - ok?
Why not just call sendto several times, with an offset into the buffer?
int sendto_bigbuffer(int sock, const void *buffer, const size_t buflen, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
size_t sendlen = MIN(buflen, 1024);
size_t remlen = buflen;
const void *curpos = buffer;
while (remlen > 0)
{
ssize_t len = sendto(sock, curpos, sendlen, flags, dest_addr, addrlen);
if (len == -1)
return -1;
curpos += len;
remlen -= len;
sendlen = MIN(remlen, 1024);
}
return buflen;
}
Something like the above function will send the buffer 1024 bytes at a time.
I have a server daemon listening on a TCP unix domain/local socket. Multiple clients running on the same machine connect to it. The daemon is also bound to a UDP Internet socket. Whenever the daemon receives any data from one of the local clients, it sends the same data to all the connected clients except the sending client. If the daemon receives data on the UDP internet socket, it needs to send that data to all the local connected clients. The sending/receiving of data works perfectly when the daemon receives data on the local socket. However, the clients do not receive any data when the server sends them data received on the UDP internet socket. The clients receive that internet data either after the server daemon is exited and the connection is closed, or, when any of the clients sends data locally to the server. The internet data is received by the clients along with the local data. I have set both local and inet sockets as blocking using fcntl(). Here is the daemon code that I have (I have removed all the unnecessary code):
while(1)
{
FD_SET(sockfd, &read_fds);
FD_SET(inet_sock, &read_fds);
for (i = 0; i < nclients; i++)
{
FD_SET(clients[i], &read_fds);
}
select(maxfd + 1, &read_fds, &write_fds, &except_fds, NULL);
/* Check for events on inet sock */
if (FD_ISSET(inet_sock, &read_fds))
{
/* Read from inet sock */
socklen = sizeof(dest_sin);
rval = recvfrom(inet_sock, buf, BUFLEN-1, MSG_DONTWAIT,
(struct sockaddr *) &dest_sin, &socklen);
buf[rval]=0;
fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf);
/* Send the message to every other client */
for(j=0; j < nclients; j++)
{
send(clients[j], buf, strlen(buf), MSG_DONTWAIT);
}
}
/* A read event on the local socket is a new connection */
if (FD_ISSET(sockfd, &read_fds))
{
socklen = sizeof(dest_sun);
/* Accept the new connection */
rval = accept(sockfd, (struct sockaddr *) &dest_sun, &socklen);
/* Add client to list of clients */
clients[nclients++] = rval;
if (rval > maxfd) maxfd = rval;
snprintf(s, BUFLEN, "You are client %d [%d]. You are now connected.\n\0",
nclients, rval);
send(rval, s, strnlen(s, BUFLEN), MSG_DONTWAIT);
}
/* Check for events from each client */
for (i = 0; i < nclients; i++)
{
fprintf(stderr,"Checking client %d [%d] for read indicator.\n",i, clients[i]);
/* Client read events */
if (FD_ISSET(clients[i], &read_fds))
{
fprintf(stderr, "Client %d [%d] marked for read.\n", i, clients[i]);
/* Read from client */
rval=recv(clients[i], buf, BUFLEN-1, MSG_DONTWAIT);
buf[rval]=0;
fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf);
/* Send the message to every other client */
for(j=0; j < nclients; j++)
{
/* Skip the sender */
if (j == i) continue;
/* Send the message */
send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT);
}
}
}
}
Here is the client code that I have:
while(1)
{
FD_SET(fileno(stdin), &read_fds);
FD_SET(sockfd, &read_fds);
select(fileno(stdin) > sockfd ? fileno(stdin)+1 : sockfd+1,
&read_fds, &write_fds, &except_fds, NULL);
if (FD_ISSET(sockfd, &read_fds))
{
/* Read from socket and display to user */
mlen = recv(sockfd, (void *)buf, BUFLEN-1, MSG_DONTWAIT);
buf[mlen]=0;
printf("Received %d bytes: %s", mlen, buf);
}
if (FD_ISSET(fileno(stdin), &read_fds))
{
fgets(buf, BUFLEN, stdin);
fprintf(stderr, "Sent %d octets to server.",
send(sockfd, (void *)buf, (size_t) strnlen(buf, BUFLEN), 0));
}
}
The goal is to have the clients receive data immediately that the daemon sends them (the data which the daemon receives on its inet socket).
EDIT: I have figured that when the daemon sends the data, the select() on the client side returns that the socket is readable, but recv() is blocking, that's the reason I'm not getting data on the client side. Any suggestions on how to fix this?
Here's the send() calls from your code, extracted and aligned:
send(clients[j], buf, strlen(buf), MSG_DONTWAIT);
send(rval, s, strnlen(s, BUFLEN), MSG_DONTWAIT);
send(clients[j], s, strlen(s, BUFLEN), MSG_DONTWAIT);
I see some inconsistencies here. Sometimes you call strlen(), sometimes strnlen(), and sometimes strlen() with two arguments (I don't even know what that's going to do).
The problem you're seeing may be related to the fact that you're not sending any information on the socket that shows where the boundaries between messages are. Over a stream socket, message boundaries are not preserved and you should take care to include appropriate framing information in your protocol so that the receiver can extract the individual messages. You cannot rely on exactly the same number of bytes coming through a recv() call as there was in a send() call. You will get the same total number of bytes in the same order (that's the point of a stream socket), but the messages might get consolidated or split up and you have no control over that.