I have app to do that send 30k byte packet in to server, receive it back (100 attempts) and counts average time of that.
It has to have 2 dif type of sockets: UDP and TCP. With UDP its working fine, but with TCP it's looping in a last while (client-side). I assume that TCP is working differently than UDP, and the packed send isn't the same that i recieve.
Please look at my code:
client (has to be run second)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#include <errno.h>
#define BUFFER_SIZE 1000
#define ATTEMPTS 10
char buf[BUFFER_SIZE];
/*
argv[1] - nazwa hosta
argv[2] - numer portu UDP
argv[3] - numer portu TCP
*/
int main(int argc, char **argv)
{
struct sockaddr_in endpoint;
int sdsocket, sdsocket2, addrlen, i, received, j=0, r_sendto, r_recvfrom;
struct hostent *he;
struct timeval time_b, time_e;
if (argc<4) {
printf("podaj nazwe hosta i numery portu jako parametry (1 UDP, 2 TCP)\n");
return 1;
}
he = gethostbyname(argv[1]);
if (he == NULL) {
printf("Nieznany host (unknown kost): %s\n",argv[1]);
return 0;
}
memset(&endpoint, 0, sizeof(endpoint));
endpoint.sin_family = AF_INET;
endpoint.sin_port = htons(atoi(argv[2]));
endpoint.sin_addr = *(struct in_addr*) he->h_addr;
addrlen = sizeof(struct sockaddr_in);
////////////// UDP //////////////////
gettimeofday(&time_b, NULL);
if ((sdsocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
perror("socket UDP() nie powiodl sie");
return 1;
}
while(ATTEMPTS>j){
r_sendto = sendto(sdsocket,
buf,
BUFFER_SIZE,
0,
(struct sockaddr*) &endpoint,
addrlen);
if (r_sendto == -1) {
perror("sendto() nie powiodl sie (failed)\n");
//close(sdsocket); //?
return 1;
}
r_recvfrom = recvfrom(sdsocket,
buf,
BUFFER_SIZE,
0,
(struct sockaddr*) &endpoint,
&addrlen);
if (r_recvfrom == -1){
perror("recvfrom() nie powidl sie (failed)\n");
break;
}
j++;
}
close(sdsocket);
gettimeofday(&time_e, NULL);
printf("Czas dla 30k-bajtowych bloków (UDP): %.6f s\n",
(((double) (time_e.tv_sec - time_b.tv_sec) * 1000000) +
((double) (time_e.tv_usec - time_b.tv_usec)))
/ (1000000.0 * ATTEMPTS));
////////////// TCP //////////////////
sleep(2);
endpoint.sin_port = htons(atoi(argv[3]));
if ((sdsocket2 = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket TCP() nie powiodl sie (failed)\n");
return 1;
}
gettimeofday(&time_b, NULL);
if (connect(sdsocket2,(struct sockaddr*) &endpoint, addrlen) < 0) {
perror("connect() nie powiodl sie");
return 0;
}
for (i=0; i<ATTEMPTS; i++) {
send(sdsocket2, buf, BUFFER_SIZE, 0);
received = 0;
while (received < BUFFER_SIZE)
{
printf("test %d\n", i);
int ret = recv(sdsocket2,
buf+received,
BUFFER_SIZE-received,
0);
if (ret <=0){
if (ret = 0){
printf("ret=0 - serwer zamknal\n");
}
else{
fprintf(stderr, "recv error: %s\n", strerror(errno));
}
break;
}
received += ret;
}
}
close(sdsocket2);
gettimeofday(&time_e, NULL);
printf("Czas dla 30k-bajtowych bloków (TCP): %.6f s\n",
(((double) (time_e.tv_sec - time_b.tv_sec) * 1000000) +
((double) (time_e.tv_usec - time_b.tv_usec)))
/ (1000000.0 * ATTEMPTS));
return 0;
}
server (has to be run first):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#define BUFFER_SIZE 1000
#define ATTEMPTS 10
char buf[BUFFER_SIZE];
/*
argv[1] - numer portu dla UDP
argv[2] - numer portu dla TCP
*/
int main(int argc, char **argv) {
struct sockaddr_in myaddr, client_addr;
int sdsocketUDP, sdsocketTCP; //sdsocket dla UDP/TCP
int addrlen, received, i, sdconnection;
socklen_t client_addrlen;
if (argc < 3) {
printf("podaj numer portu jako parametry (1 UDP, 2 TCP)\n");
return 1;
}
sdsocketUDP = socket(AF_INET, SOCK_DGRAM, 0);
addrlen = sizeof(struct sockaddr_in);
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(atoi(argv[1]));
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sdsocketUDP, (struct sockaddr*) &myaddr, addrlen) < 0) {
perror("bind() nie powiodl sie (failed)\n");
return 1;
}
client_addrlen = sizeof(struct sockaddr_in); //???
printf("test1\n");
////////////// UDP //////////////////
memset(buf, 0, BUFFER_SIZE);
for (i = 0; i < ATTEMPTS; i++) {
received = recvfrom(sdsocketUDP,
buf,
BUFFER_SIZE,
0,
(struct sockaddr*) &client_addr,
&client_addrlen);
if (received == -1) {
perror("recvfrom() nie powiodl sie");
// close(sdsocketUDP); //?
return 1;
}
sendto(sdsocketUDP,
buf,
BUFFER_SIZE,
0,
(struct sockaddr*) &client_addr,
client_addrlen);
}
close(sdsocketUDP);
////////////// TCP //////////////////
//myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(atoi(argv[2]));
//myaddr.sin_addr.s_addr = INADDR_ANY;
sdsocketTCP = socket(AF_INET, SOCK_STREAM, 0);
// zmienione addrlen na sizeof(myaddr)
if (bind(sdsocketTCP, (struct sockaddr*) &myaddr, addrlen) < 0) {
perror("bind() nie powiodl sie (failed)\n");
return 1;
}
client_addrlen = sizeof(struct sockaddr_in);
if (sdsocketTCP < 0) {
perror("socket TCP() nie powiodl sie (failed)\n");
return 1;
}
if (listen(sdsocketTCP, 10) < 0) {
perror("listen() nie powiodl sie (failed)\n");
return 1;
}
printf("Czekam na polaczenie (I am waiting for connection)...\n");
while ((sdconnection =
accept(sdsocketTCP,
(struct sockaddr*) &client_addr,
&client_addrlen)) >= 0)
{
memset(buf, 0, BUFFER_SIZE);
received = 0;
while (received < BUFFER_SIZE) {
received += recv(sdconnection,
buf + received,
BUFFER_SIZE - received,
0);
}
send(sdconnection, buf, BUFFER_SIZE, 0);
close(sdconnection);
}
close(sdsocketTCP);
return 0;
}
I tried changing number of bytes send in case of blocks being partitioned, adding sleep in client in case server isn't responding/answering on time, but didn't work.
Chat GPT can't tell the answer or hint. I think issue is with it how TCP works.
Cheers.
Your TCP server seems to close the accepted TCP connection after receiving BUFFER_SIZE bytes:
while ((sdconnection =
accept(sdsocketTCP,
(struct sockaddr*) &client_addr,
&client_addrlen)) >= 0)
{
...
while (received < BUFFER_SIZE) {
...
}
....
close(sdconnection);
}
Because the TCP client try to use the same TCP connection for ATTEMPTS * BUFFER_SIZE bytes, the server closes the connection too early, and starts waiting next connection.
Quick and dirty(?) fix for the server would be:
Echo all data from the client until the TCP connection is closed (recv() returns 0 or -1). For example something like this:
while ((sdconnection =
accept(sdsocketTCP,
(struct sockaddr*) &client_addr,
&client_addrlen)) >= 0)
{
while (1)
int len = recv(sdconnection, buf, BUFFER_SIZE, 0);
if (len <= 0)
break;
send(sdconnection, buf, len, 0);
};
close(sdconnection);
}