I'm trying to develop a streaming system sending multiple images to a receiving socket, which displays them. However, for some reason I can't understand, my code gets blocked at the send function after sending about 3 images. This is a snippet of my code so far:
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
bzero(buffer,256);
for(int i=10;i<51;i++){
std::stringstream sstm;
sstm << filename << i << ext;
result = sstm.str();
cout << result << endl;
Mat image = imread(result, CV_LOAD_IMAGE_COLOR);
image = (image.reshape(0,1));
int imgSize = image.total()*image.elemSize();
n = send(sockfd, image.data, imgSize, 0);
}
Tried to debug it, and, as I said, it gets blocket at the last line, the send function. I wonder if there's a limit on how much information can you transmit through a socket. If I move the for sentence back before the socket creation, it works like a charm, but i'm not going to create a bizillion sockets. Any help?
The send() call will block if the TCP window size goes to zero. This is almost always a result of the other side of the connection not consuming the data from a recv() call.
It's also entirely possible that imgSize is extremely huge and it just simply takes that long for the receiver to consume the stream.
You didn't share any code from the receiver side, so it's difficult to say.
I would suggest more debug spew (print statements) showing the value of imgSize and the return value of the send call. Ditto for the recv side.
Do note - that just because you sent imgSize bytes in one send call, the remote receiver may not receiver all those bytes within a single call to recv().
Related
I'm trying to build a block that acts as server and client to send and receive data (2 duplicate versions in 2 different computers) through a TCP connection.
This is what I did and I'm trying to test using the windows commandd line "netstat -ab" to try to find the tcp connection but I can't find it.
Apart from the given error, what am i doing wrong?
bool IPTunnel::runBlock(void) {
int ready =
inputSignals[0]->ready(); // int ready2 = inputTCPConnetion[0]->ready();
// server
SOCKET sockfd, newsockfd;
int portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
SOCKET n;
// create a socket(int domain, int type, int protocol)
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) printf("\n ERROR opening socket");
// bzero((char *)&serv_addr, sizeof(serv_addr));
portno = 5500;
serv_addr.sin_family = AF_INET;
char ipad[10] = "127.0.0.1";
serv_addr.sin_addr.s_addr = *ipad; // INADDR_ANY;
serv_addr.sin_port = htons(portno);
// if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
auto sd = bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
// if (sd < 0)
// printf("\n ERROR on binding");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
if(newsockfd < 0) printf("ERROR on accept");
printf("server: got connection from %s port %d\n",
inet_ntop(serv_addr.sin_family, &ipad, buffer, clilen),
ntohs(cli_addr.sin_port));
send(newsockfd, "Hello, world!\n", 13, 0);
// bzero(buffer, 256);
n = _read(newsockfd, buffer, 255);
if(n < 0) printf("ERROR reading from socket");
printf("Here is the message: %s\n", buffer);
while(true) {
}
// close(newsockfd);
// close(sockfd);
return 0;
}
This is the error that gives: Unhandled exception at 0x00007FFE5031B7EC (ucrtbased.dll) in ip_tunnel.exe: An invalid parameter was passed to a function that considers invalid parameters fatal.
in the _read function...
Well, this line is definitely wrong:
serv_addr.sin_addr.s_addr = *ipad; //INADDR_ANY;
If you want to receive incoming TCP connections on the loopback device, you should do something more like this:
serv_addr.sin_addr.s_addr = inet_aton("127.0.0.1");
(or if you want them to be received from any connected network device, specify INADDR_ANY instead)
Also, make sure you called WSAStartup() at the beginning of your program, Windows sockets won't work correctly if you haven't done that.
One last nitpick:
while(true){}
is not a good way to pause execution of your program. For one thing, it will typically spin a CPU at 100% usage, which is very inefficient, and for another, it invokes undefined behavior according to the C++ standard.
A better way to do get that behavior would be something like:
while(true) {Sleep(1000);}
Also this part is wrong/weird:
SOCKET n;
[...]
n = _read(newsockfd, buffer, 255);
... in that _read doesn't return a SOCKET, it returns an int. I think you meant to declare int n; instead.
One last potential problem: if your call to bzero(buffer, 256); is commented out, then it's quite possible for buffer to contain no zero-bytes after the _read() call returns, in which case your printf("Here is the message: %s\n", buffer); call afterwards could read right past the end of the buffer array and out into the wild blue yonder of other memory, potentially causing a crash (or at least causing a lot of garbage bytes to be printed). The fix is to make sure the buffer array contains a 0/NUL byte at the end of the valid bytes that were placed there by the _read() call.
I'm working on a webserver framework in C++ mostly for my own understanding, but I want to optimize it as well.
My question is is it faster to write multiple char arrays to the TCP connection for every html response or to spend the time to concatenate up front and only write to the TCP connection once. I was thinking about benchmarking it, but I am not quite sure how to go about it.
This is my first post on stackoverflow, although I have benefitted from the website very often!
Thanks!
Here is what I am talking about for sending many char arrays individually. The alternate would be concatenate all of these char arrays into one char array then sending that.
int main() {
sockaddr_in address;
int server_handle;
int addrlen = sizeof(address);
if ((server_handle = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("cannot create socket");
exit(0);
}
memset((char *) &address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(PORT);
if (bind(server_handle, (sockaddr *) &address, (socklen_t) addrlen) < 0)
{
perror("bind failed");
exit(0);
}
if (listen(server_handle, 3) < 0)
{
perror("In listen");
exit(EXIT_FAILURE);
}
while(1) {
std::cout << "\n+++++++ Waiting for new connection ++++++++\n\n";
int client_handle;
if ((client_handle = accept(server_handle, (struct sockaddr *)&address, (socklen_t *) &addrlen))<0)
{
perror("In accept");
exit(EXIT_FAILURE);
}
// read and respond to client request
char buffer[30000] = {0};
int bytesRead = read(client_handle, buffer, 30000);
char * httptype = "HTTP/1.1 ";
char * status = "200 \n";
char * contenttype = "Content-Type: text/html \n";
char * contentlength = "Content-Length: 21\n\n";
char * body = "<h1>hello world!</h1>";
write(client_handle, httptype, 9);
write(client_handle, status, 5);
write(client_handle, contenttype, 26);
write(client_handle, contentlength, 20);
write(client_handle, body, 21);
std::cout << "------------------Response sent-------------------\n";
close(client_handle);
}
}
If you want to send multiple buffers with a single write call you can use vectored IO (aka scatter/gather IO) as the manual suggests:
char *str0 = "hello ";
char *str1 = "world\n";
struct iovec iov[2];
ssize_t nwritten;
iov[0].iov_base = str0;
iov[0].iov_len = strlen(str0);
iov[1].iov_base = str1;
iov[1].iov_len = strlen(str1);
nwritten = writev(STDOUT_FILENO, iov, 2);
In fact it writing to a socket is not really different from writing to a file descriptor. And the fwrite function was introduced to the C library for a reason: write (be it to a TCP connection or to a file descriptor) involve a system call on common OS and a context change user/kernel. That context change has some overhead, mainly if you write small chunks of data.
On the other hand, if you write larger chunks of data in sizes that are close to the physical size for the underlying system call (disk buffer for a file descriptor, or max packet size for a network socket), the fwrite call or in your example the code concatenating char arrays will not really lower the system overhead and will just add some user code processing.
TL/DR: this depends on the average size of what you write. The smaller it is, the higher benefit of concatenating the date in larger chunks before writing. And remember: this is a low level optimization that should only be considered if you have identified a performance bottleneck or if the code could be used in a broadly distributed library.
I am developing a C++ app in openSUSE 12.3 and one of it's part is responsible to send data to a device via Socket (in LAN). I am using this code
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *printer;
portno = 9100;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) error("ERROR opening socket\n");
printer = gethostbyname("100.0.69.23");
if(printer == NULL) error("No such device on 100.0.69.23\n");
//set bit set to zero
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *) printer->h_addr, (char *) &serv_addr.sin_addr.s_addr, printer- >h_length);
serv_addr.sin_port = htons(portno);
if(connect(sockfd, (struct sockaddr *) & serv_addr, sizeof(serv_addr)) < 0)
{error("ERROR connecting");
return;
}
n = write(sockfd, data, datalenght);
if(n < 0) error("ERROR sending command to printer");
n = read(sockfd, buffer, 200);
I think the code is correct but the connect function returns -1 and seems that could not connect to the device (printer) . This code was written in openSUSE 11 and was working OK and I could send/receive data to device but when I copy/paste it to new system (openSUSE 12.3) it gives me failure in connecting. I ping result on the specific IP which is in use show that device is reachable via LAN
I think you should consider the possibility that hostent returned by gethostbyname function might have AF_INET6 address family (in which case it will be IPv6 instead of IPv4 address).
http://linux.die.net/man/3/gethostbyname
So you can either use GNU extension function gethostbyname2 function that will allow you to specify address family.
printer = gethostbyname2("100.0.69.23", AF_INET);
Or instead you can use getaddrinfo function, as gethostbyname function is said to be obsolete, by the documentation.
As already mentioned, you are checking for printer == NULL before initializing it. I think you meant the following instead:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("ERROR opening socket\n");
printer = gethostbyname("100.0.69.23");
...
Also the structure of the code seems to indicate that when you want to send a command to the printer you connect(), write() then read(), which is OK if you are only ever sending one command, but suboptimal if you are sending multiple commands. In the latter case you want to separate the connect() from the write() as it's fairly expensive to connect so you want to do it just once.
I have a loop which keeps writing data to a client through TCP/IP. The connection is opened as follows:
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
The following line is executed continuously in a loop (with sleep of 0.1 sec) in order to write the data to the client:
n = write(newsockfd,data.c_str(),data.length()+1); //+1 to include NULL in null terminated string
if(n>=0)
{
cout<<"success"<<endl;
}
else
{
cout<<"Fail"<<endl;
close(newsockfd);
newsockfd = -1;
}
I want the server to become reading for receiving a new connections if the connection is broken for any reason. So if writing fails, I get ready again to accept a new connection with the first command.
My problem is the following: the method succeeds for the first time, so if the connection is broken from the client, write() returns a negative number and I know immediately that the connection has a problem, so I close it and expect a new one. The server receives the new connection, but at the next time when using write(), the program crashes immediately.
Why does this happen? Please help, I'm new in TCP/IP stuff.
Please ask for more information if you require it.
Requested from helpers:
Stack trace:
Error: signal 13:
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x402155]
/lib/x86_64-linux-gnu/libc.so.6(+0x364a0)[0x7ffc57ac04a0]
/lib/x86_64-linux-gnu/libpthread.so.0(write+0x10)[0x7ffc5836dcb0]
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x4023b6]
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x401b54]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7ffc57aab76d]
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x402081]
Variable definitions: it's a class:
Body:
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
Constructor starts the stuff:
LinuxTCPServer::LinuxTCPServer(int port, bool nonblocking)
{
if(nonblocking)
sockfd = socket(AF_INET, SOCK_NONBLOCK | SOCK_STREAM, 0);
else
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = port;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
}
Assuming Linux >= 2.2, replace this:
n = write(newsockfd,data.c_str(),data.length()+1);
with this:
n = send(newsockfd, data.c_str(), data.length()+1, MSG_NOSIGNAL);
send(2) will then return -1 with errno set to EPIPE, rather than generating a fatal SIGPIPE. Alternatively, ignore SIGPIPE.
When you receive the SIGPIPE, the connection behind newsockfd has been broken. We don't have enough code to reproduce the problem, client and server, so it's rather moot to say what might actually be wrong. However, converting SIGPIPEs to EPIPEs will at least give your server a chance to handle the broken connection.
Your stack trace indicates that the program is crashing with signal 13, which means you have a broken pipe.
That would indicate that your connection is broken, but you are still trying to write to it. See this thread for why that might causes the broken pipe error: What causes the Broken Pipe Error?
Now, on how to solve the issue, I suspect you're not actually getting a proper connection setup on your 'accept' call. Make sure you check the status of your 'accept' call before calling write.
The problems that are causing your accept call to fail are likely on the other side of the connection I think.
I've been trying to send a packet from a client to a server via sockets. With the help of some of the tips I have made quite bit of progress in my code. However, the server only receives eight bytes from the client and prints them on the console whereas at my client side, It seems that it has sent everything.
Now I am not sure whether the problem is at the sending side or the receiving side. My hunch is that something is wrong at my client side. Could someone please help in verifying my assumption?
Client code:
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
data_struct client_data;
struct packet
{
long int srcID;
long int destID;
int pver;
int profiles;
int length;
long int data;
};
if (argc < 3) {
fprintf(stderr,"usage: %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]); //Convert ASCII to integer
sockfd = socket(AF_INET, SOCK_STREAM, 0); // socket file descriptor
if (sockfd < 0)
error("ERROR DETECTED !!! Problem in opening socket\n");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR DETECTED !!!, no such server found \n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr)); //clear the memory for server address
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
printf("Client 1 trying to connect with server host %s on port %d\n", argv[1], portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR in connection");
printf("SUCCESS !!! Connection established \n");
char buffer[256];
struct packet *pkt = (struct packet *) buffer;
char *payload = buffer + sizeof(struct packet);
long double packet_size;
printf("Started Creating packet\n");
pkt->srcID = 01;
pkt->destID = 02;
pkt->pver = 03;
pkt->profiles = 01;
pkt->length = 16;
pkt->data = 1; 2; 3; 4; 5; 6; 7; 8;
{
if (send(sockfd,pkt,sizeof(packet_size),0) <0)
printf ("error\n");
else
printf ("packet send done");
}
return 0;
}
Server code:
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
struct sockaddr_in serv_addr, cli_addr;
int n;
char wish;
long int SrcID;
long int DestID;
int Pver;
int Profiles;
long int Data;
int Length;
char bytes_to_receive;
int received_bytes;
struct packet
{
long int srcID;
long int destID;
int pver;
int profiles;
int length;
long int data;
};
if (argc < 2) {
fprintf(stderr,"usage: %s port_number1",argv[0]);
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR DETECTED !!! Problem in opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR DETECTED !!! There was a problem in binding");
listen(sockfd, 10);
clilen = sizeof(cli_addr);
printf("Server listening on port number %d...\n", serv_addr.sin_port);
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR DETECTED !!! the connection request was not accepted");
char buffer[256];
struct packet *pkt = (struct packet *) buffer;
char *payload = buffer + sizeof(struct packet);
long double packet_size;
bytes_to_receive = sizeof(packet_size);
received_bytes = 0;
int rc =0;
while ((rc = recv(newsockfd,pkt,sizeof(packet_size),0)) > 0)
{
received_bytes+=rc;
SrcID = pkt->srcID;
DestID = pkt->destID;
Pver = pkt->pver ;
Profiles = pkt->profiles;
Length = pkt->length;
Data = pkt->data;
printf("Data Received from Client_1 are :\n");
printf("Source ID: %ld\n", SrcID);
printf("Destination ID: %ld\n", DestID);
printf("profile Version: %d\n", Pver);
printf("No of Profiles: %d\n", Profiles);
printf("Length: %d\n", Length);
printf("data : %ld\n", Data);
}
if (rc == 0)
{
printf("Connection closed by Server\n");
printf("Bytes received: %d\n",received_bytes);
}
if (rc == -1)
{
perror("recv");
}
{
if (close(newsockfd) == -1) {
error("Error closing connection with client 1");
}
printf("Connection with client 1 has been closed\n");
}
return 0;
}
The output that I see on the client's console is:
Client Side: Client 1 trying to connect with server host 130.191.166.230 on port 1234
SUCCESS !!! Connection established
Started Creating packet
packet send done
and on the server's console I see:
Server Side: Data Received from Client_1 are :
Source ID: 1
Destination ID: 2
profile Version: 0
No of Profiles: 1074462536
Length: 0
data : 0
Connection closed by Server
Bytes received: 8
Connection with client 1 has been closed
First of all
recv(newsockfd,pkt,sizeof(packet_size),0)) /* What is packet_size ? */
recv(newsockfd,pkt,sizeof(struct packet),0)) /* You probably mean this. */
That might solve your problems, but there are a few issues with the way you are using TCP sockets.
But at my client side, it prints that it has sent everything
Where ? I don't see you actually checking the number of bytes sent. send(2) can return after sending less that you asked it to.
It shows me that only 8 bytes were sent by Client and prints them out.
TCP is a stream-oriented protocol. You send bytes and they arrive, in the same order. So when you recv(2) something, you might get less (or more than you wrote). So, the following can be true:
client:
send 100 bytes
send 400 bytes
server:
recv 50 bytes
recv 150 bytes
recv 250 bytes
recv 50 bytes
The number of send and recv calls need not be identical when using TCP.
When you call send the function returns the number of bytes actually sent and this number can be less than the number of bytes you wanted to send. So every time you want to send something there must be a loop like the following
bool sendBuffer(SOCKET s, unsigned char *buf, int size)
{
while (size > 0)
{
int sz = send(s, buf, size,0);
if (sz < 0) return false; // Failure
size -= sz; // Decrement number of bytes to send
buf += sz; // Advance read pointer
}
return true; // All buffer has been sent
}
and a similar loop must be done when receiving (in other words recv can return less bytes than what you are asking for).
If you don't make these loops the risk is that everything apparently will work anyway (until the size of an ethernet packet) when you work on your local machine or even over a LAN, but things will not work when working across the internet.
Note also that as other answers pointed out you asked to send sizeof(packet_size) i.e. the number of bytes required to store that variable, not the size of the structure.
There is an informal rule that nobody is allowed to write any software that uses TCP until they memorize this sentence and can fully explain what it means: "TCP is a byte-stream protocol that does not preserve application message boundaries."
What that means is that TCP only ensures that you get out the same bytes you put in and in the same order. It does not "glue" the bytes together in any way.
Before you write any code that uses TCP, you should either use a protocol that is already designed (such as IMAP or HTTP) or design one yourself. If you design one yourself, you should write out a protocol specification. It should specifically define what a protocol-level message will consist of at the byte level. It should specifically state how the receiver finds the ends of messages, and so on.
This may seem a little silly for simple applications, but trust me, it will pay off massively. Otherwise, it's almost impossible to figure out why things aren't work because if the server and client don't quite get along, there's no arbiter to say what's right.
I don't specialise in socket programming but there are a few things I've noticed. As far as I'm aware, I don't think you can send structs over sockets that easily. You may wish to consider a different method.
NB, when using send/recv you're also determing the sizeof packet_size, and not the sizeof the struct.
Googling brought up this about sending structs over sockets: http://ubuntuforums.org/showthread.php?t=613906