我有一个应用程序可以将 30k 字节数据包发送到服务器,接收回来(100 次尝试)并计算其平均时间。
它必须有 2 种不同类型的套接字:UDP 和 TCP。使用 UDP 时,它工作正常,但使用 TCP 时,它会在最后一段时间(客户端)循环。我假设 TCP 的工作方式与 UDP 不同,并且打包发送的数据与我收到的数据不同。
请看我的代码:
客户端(必须第二个运行)
#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;
}
服务器(必须先运行):
#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;
}
我尝试更改块被分区时发送的字节数,在客户端中添加睡眠以防服务器未按时响应/应答,但没有成功。
聊天GPT无法说出答案或提示。我认为问题在于 TCP 如何工作。
干杯。
您的 TCP 服务器似乎在收到 BUFFER_SIZE 字节后关闭了已接受的 TCP 连接:
while ((sdconnection =
accept(sdsocketTCP,
(struct sockaddr*) &client_addr,
&client_addrlen)) >= 0)
{
...
while (received < BUFFER_SIZE) {
...
}
....
close(sdconnection);
}
由于 TCP 客户端尝试使用同一个 TCP 连接 30 * BUFFER_SIZE 字节,服务器过早关闭连接,并开始等待下一个连接。