From b09a29b7e8640d17277c58e0c94dae12beaa00a2 Mon Sep 17 00:00:00 2001 From: CGH0S7 <776459475@qq.com> Date: Sat, 10 Jan 2026 10:54:46 +0800 Subject: [PATCH] tcp/quic lab patched --- network/tcpquiclab/Makefile | 16 ++- network/tcpquiclab/README_LINUX.md | 37 ++++- network/tcpquiclab/README_LINUX_CN.md | 37 ++++- network/tcpquiclab/quic_multi_client | Bin 0 -> 29448 bytes network/tcpquiclab/quic_multi_client.c | 169 +++++++++++++++++++++++ network/tcpquiclab/quic_multi_server | Bin 0 -> 30208 bytes network/tcpquiclab/quic_multi_server.c | 179 +++++++++++++++++++++++++ network/tcpquiclab/tcp_multi_client | Bin 0 -> 19736 bytes network/tcpquiclab/tcp_multi_client.c | 70 ++++++++++ network/tcpquiclab/tcp_multi_server | Bin 0 -> 22016 bytes network/tcpquiclab/tcp_multi_server.c | 118 ++++++++++++++++ 11 files changed, 618 insertions(+), 8 deletions(-) create mode 100755 network/tcpquiclab/quic_multi_client create mode 100644 network/tcpquiclab/quic_multi_client.c create mode 100755 network/tcpquiclab/quic_multi_server create mode 100644 network/tcpquiclab/quic_multi_server.c create mode 100755 network/tcpquiclab/tcp_multi_client create mode 100644 network/tcpquiclab/tcp_multi_client.c create mode 100755 network/tcpquiclab/tcp_multi_server create mode 100644 network/tcpquiclab/tcp_multi_server.c diff --git a/network/tcpquiclab/Makefile b/network/tcpquiclab/Makefile index f688051..7e5aaac 100644 --- a/network/tcpquiclab/Makefile +++ b/network/tcpquiclab/Makefile @@ -2,7 +2,7 @@ CC = gcc CFLAGS = -Wall -g LDFLAGS = -lquiche -ldl -lpthread -lm -all: tcp_server tcp_client quic_server quic_client tcp_perf_server tcp_perf_client quic_perf_server quic_perf_client +all: tcp_server tcp_client quic_server quic_client tcp_perf_server tcp_perf_client quic_perf_server quic_perf_client tcp_multi_server tcp_multi_client quic_multi_server quic_multi_client tcp_server: tcp_server.c $(CC) $(CFLAGS) -o tcp_server tcp_server.c @@ -28,5 +28,17 @@ quic_perf_server: quic_perf_server.c quic_perf_client: quic_perf_client.c $(CC) $(CFLAGS) -o quic_perf_client quic_perf_client.c $(LDFLAGS) +tcp_multi_server: tcp_multi_server.c + $(CC) $(CFLAGS) -o tcp_multi_server tcp_multi_server.c -lpthread + +tcp_multi_client: tcp_multi_client.c + $(CC) $(CFLAGS) -o tcp_multi_client tcp_multi_client.c -lpthread + +quic_multi_server: quic_multi_server.c + $(CC) $(CFLAGS) -o quic_multi_server quic_multi_server.c $(LDFLAGS) + +quic_multi_client: quic_multi_client.c + $(CC) $(CFLAGS) -o quic_multi_client quic_multi_client.c $(LDFLAGS) + clean: - rm -f tcp_server tcp_client quic_server quic_client tcp_perf_server tcp_perf_client quic_perf_server quic_perf_client + rm -f tcp_server tcp_client quic_server quic_client tcp_perf_server tcp_perf_client quic_perf_server quic_perf_client tcp_multi_server tcp_multi_client quic_multi_server quic_multi_client diff --git a/network/tcpquiclab/README_LINUX.md b/network/tcpquiclab/README_LINUX.md index 5219954..87b6623 100644 --- a/network/tcpquiclab/README_LINUX.md +++ b/network/tcpquiclab/README_LINUX.md @@ -103,7 +103,38 @@ We use Linux `tc` (Traffic Control) with `netem` instead of `clumsy`. sudo tc qdisc del dev lo root ``` -### 3.3 & 3.4 Advanced Tests +### 3.3 Advanced Test: Multiplexing vs Multi-Connection -- **Multiplexing:** The current `quic_perf_client` uses a single stream (Stream ID 4). You can modify the code to launch multiple streams in parallel to test head-of-line blocking resilience. -- **Network Recovery:** Use `tc` to drop 100% packets (`loss 100%`) for 30 seconds during a long transfer, then remove the rule (`del`) to see if the connection recovers. +This task compares the performance of 5 parallel TCP connections against a single QUIC connection with 5 concurrent streams. + +**Scenario 1: TCP Multi-Connection** +Establish 5 TCP connections simultaneously, each transferring 20MB (Total 100MB). + +1. Start TCP Multi-Connection Server: + ```bash + ./tcp_multi_server + ``` +2. Run TCP Multi-Connection Client: + ```bash + ./tcp_multi_client + ``` +3. Record total time and throughput from the server output. + +**Scenario 2: QUIC Single-Connection Multi-Streaming** +Establish 1 QUIC connection and open 5 streams concurrently, each transferring 20MB (Total 100MB). + +1. Start QUIC Multi-Stream Server: + ```bash + ./quic_multi_server + ``` +2. Run QUIC Multi-Stream Client: + ```bash + ./quic_multi_client + ``` +3. Record the performance statistics. + +**Analysis Points:** +- Compare completion times in a normal network. +- Use `tc` to simulate packet loss (e.g., 5%). Observe how QUIC's multiplexing avoids TCP's Head-of-Line (HoL) blocking, where a single lost packet in one TCP connection doesn't stall the other streams in QUIC. + +### 3.4 Network Recovery diff --git a/network/tcpquiclab/README_LINUX_CN.md b/network/tcpquiclab/README_LINUX_CN.md index 0dcd0af..85d595f 100644 --- a/network/tcpquiclab/README_LINUX_CN.md +++ b/network/tcpquiclab/README_LINUX_CN.md @@ -103,7 +103,38 @@ make sudo tc qdisc del dev lo root ``` -### 3.3 & 3.4 进阶测试 +### 3.3 进阶测试:多路复用与多连接对比 -- **多路复用:** 当前的 `quic_perf_client` 使用单个流 (Stream ID 4)。您可以修改代码并行启动多个流,以测试 QUIC 解决队头阻塞问题的能力。 -- **网络恢复:** 在长传输过程中,使用 `tc` 设置 100% 丢包 (`loss 100%`) 持续 30 秒,然后删除规则 (`del`),观察连接是否能恢复传输。 +本实验任务要求对比 TCP 多连接与 QUIC 多流复用的性能。 + +**场景 1: TCP 多连接并发** +同时建立 5 个 TCP 连接,每个连接传输 20MB 数据 (总计 100MB)。 + +1. 启动 TCP 多连接服务器: + ```bash + ./tcp_multi_server + ``` +2. 启动 TCP 多连接客户端: + ```bash + ./tcp_multi_client + ``` +3. 记录服务器输出的总时间与吞吐量。 + +**场景 2: QUIC 单连接多流复用** +建立 1 个 QUIC 连接,在其中同时开启 5 个流 (Stream),每个流传输 20MB 数据 (总计 100MB)。 + +1. 启动 QUIC 多流服务器: + ```bash + ./quic_multi_server + ``` +2. 启动 QUIC 多流客户端: + ```bash + ./quic_multi_client + ``` +3. 记录服务器输出的统计数据。 + +**分析重点:** +- 在正常网络下,两者的总耗时差异。 +- 使用 `tc` 模拟丢包 (如 5%) 后,对比两者性能下降的幅度。QUIC 的多流复用应能避免 TCP 的“队头阻塞”问题 (即一个包丢失不影响其他流的传输),从而在丢包环境下表现更优。 + +### 3.4 网络恢复测试 diff --git a/network/tcpquiclab/quic_multi_client b/network/tcpquiclab/quic_multi_client new file mode 100755 index 0000000000000000000000000000000000000000..4e44fc9df290022219e30dfed5a6221743eec6ed GIT binary patch literal 29448 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 literal 0 HcmV?d00001 diff --git a/network/tcpquiclab/quic_multi_client.c b/network/tcpquiclab/quic_multi_client.c new file mode 100644 index 0000000..bfa84cd --- /dev/null +++ b/network/tcpquiclab/quic_multi_client.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_DATAGRAM_SIZE 1350 +#define TOTAL_MB 100 +#define NUM_STREAMS 5 +#define MB_PER_STREAM (TOTAL_MB / NUM_STREAMS) + +typedef struct { + uint64_t stream_id; + long long bytes_sent; + long long bytes_total; + bool finished; +} StreamState; + +int main(int argc, char *argv[]) { + quiche_config *config = quiche_config_new(QUICHE_PROTOCOL_VERSION); + if (config == NULL) return -1; + + quiche_config_verify_peer(config, false); + quiche_config_set_application_protos(config, (uint8_t *) "\x0ahq-interop\x05hq-29\x05hq-28\x05hq-27\x08http/0.9", 38); + quiche_config_set_max_idle_timeout(config, 10000); + quiche_config_set_max_recv_udp_payload_size(config, MAX_DATAGRAM_SIZE); + quiche_config_set_max_send_udp_payload_size(config, MAX_DATAGRAM_SIZE); + quiche_config_set_initial_max_data(config, 1024 * 1024 * 500); + quiche_config_set_initial_max_stream_data_bidi_local(config, 1024 * 1024 * 100); + quiche_config_set_initial_max_stream_data_bidi_remote(config, 1024 * 1024 * 100); + quiche_config_set_initial_max_streams_bidi(config, 100); + quiche_config_set_cc_algorithm(config, QUICHE_CC_RENO); + + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) return -1; + + struct sockaddr_in peer_addr; + memset(&peer_addr, 0, sizeof(peer_addr)); + peer_addr.sin_family = AF_INET; + peer_addr.sin_port = htons(8889); + inet_pton(AF_INET, "100.115.45.1", &peer_addr.sin_addr); + + if (connect(sock, (struct sockaddr *)&peer_addr, sizeof(peer_addr)) < 0) return -1; + + struct sockaddr_in local_addr; + socklen_t local_addr_len = sizeof(local_addr); + if (getsockname(sock, (struct sockaddr *)&local_addr, &local_addr_len) < 0) return -1; + + int flags = fcntl(sock, F_GETFL, 0); + fcntl(sock, F_SETFL, flags | O_NONBLOCK); + + uint8_t scid[QUICHE_MAX_CONN_ID_LEN]; + int rng = open("/dev/urandom", O_RDONLY); + read(rng, scid, sizeof(scid)); + close(rng); + + quiche_conn *conn = quiche_connect("100.115.45.1", (const uint8_t *)scid, sizeof(scid), (struct sockaddr *)&local_addr, local_addr_len, (struct sockaddr *)&peer_addr, sizeof(peer_addr), config); + if (conn == NULL) return -1; + + printf("Connecting to QUIC Multi-Stream Server...\n"); + printf("Sending %d streams, %d MB each (Total %d MB)...\n", NUM_STREAMS, MB_PER_STREAM, TOTAL_MB); + + uint8_t buf[65535]; + uint8_t out[MAX_DATAGRAM_SIZE]; + uint8_t payload[4096]; + memset(payload, 'C', sizeof(payload)); + + // Initialize stream states + StreamState streams[NUM_STREAMS]; + for (int i = 0; i < NUM_STREAMS; i++) { + streams[i].stream_id = 4 * i + 4; // 4, 8, 12, 16, 20... (Client Bidi) or simple increment if library handles it? + // Note: Client initiated bidi streams usually start at 0, then 4, 8... + // but let's stick to explicit IDs or check quiche docs. + // Quiche expects us to use IDs. 0, 4, 8, 12, 16 are valid client bidi. + streams[i].stream_id = i * 4; + streams[i].bytes_sent = 0; + streams[i].bytes_total = (long long)MB_PER_STREAM * 1024 * 1024; + streams[i].finished = false; + } + + bool all_finished = false; + + while (1) { + ssize_t read_len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT); + if (read_len > 0) { + quiche_conn_recv(conn, buf, read_len, &(quiche_recv_info){ + .to = (struct sockaddr *)&local_addr, + .to_len = local_addr_len, + .from = (struct sockaddr *)&peer_addr, + .from_len = sizeof(peer_addr), + }); + } + + if (quiche_conn_is_closed(conn)) { + printf("Connection closed.\n"); + break; + } + + if (quiche_conn_is_established(conn)) { + all_finished = true; + for (int i = 0; i < NUM_STREAMS; i++) { + if (!streams[i].finished) { + all_finished = false; + // Try to send on this stream + while (streams[i].bytes_sent < streams[i].bytes_total) { + uint64_t err_code = 0; + // Determine payload size + ssize_t sent = quiche_conn_stream_send(conn, streams[i].stream_id, payload, sizeof(payload), false, &err_code); + if (sent > 0) { + streams[i].bytes_sent += sent; + if (streams[i].bytes_sent >= streams[i].bytes_total) { + // Send FIN + quiche_conn_stream_send(conn, streams[i].stream_id, NULL, 0, true, &err_code); + streams[i].finished = true; + printf("Stream %ld finished.\n", streams[i].stream_id); + } + } else { + // E.g. Done (congestion) or Stream Limit + break; + } + } + } + } + + if (all_finished) { + // Wait a bit to ensure ACKs or just exit? + // Ideally wait for close, but let's just loop a bit or wait for idle. + // Actually the server will likely not close connection, we can just idle. + } + } + + bool has_outgoing = false; + while (1) { + quiche_send_info send_info; + ssize_t written = quiche_conn_send(conn, out, sizeof(out), &send_info); + if (written == QUICHE_ERR_DONE) break; + if (written < 0) break; + send(sock, out, written, 0); + has_outgoing = true; + } + + quiche_conn_on_timeout(conn); + if (!has_outgoing && !all_finished) usleep(100); + if (all_finished && !has_outgoing) { + // Maybe wait for connection close or timeout + usleep(100000); // Wait 100ms + // quiche_conn_close(conn, true, 0, "Done", 4); + // break; + // Let's keep it alive for a moment for server to ack then exit + static int linger = 0; + if (linger++ > 20) { + printf("All streams finished. Closing.\n"); + uint8_t reason[] = "done"; + quiche_conn_close(conn, true, 0, reason, sizeof(reason)); + break; + } + } + } + + quiche_conn_free(conn); + quiche_config_free(config); + return 0; +} diff --git a/network/tcpquiclab/quic_multi_server b/network/tcpquiclab/quic_multi_server new file mode 100755 index 0000000000000000000000000000000000000000..73b466349f743e3d0ca4c7af5ba58dbb4ce5be82 GIT binary patch literal 30208 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 F@n2$oo%8?z literal 0 HcmV?d00001 diff --git a/network/tcpquiclab/quic_multi_server.c b/network/tcpquiclab/quic_multi_server.c new file mode 100644 index 0000000..c25bdcd --- /dev/null +++ b/network/tcpquiclab/quic_multi_server.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_DATAGRAM_SIZE 1350 +#define LOCAL_CONN_ID_LEN 16 +#define TARGET_MB 100 // Target total MB to receive + +typedef struct { + int sock; + struct sockaddr_storage peer_addr; + socklen_t peer_addr_len; + quiche_conn *conn; + long long total_bytes; + struct timespec start_time; + int timer_started; +} Client; + +int main(int argc, char *argv[]) { + quiche_config *config = quiche_config_new(QUICHE_PROTOCOL_VERSION); + if (config == NULL) return -1; + + quiche_config_load_cert_chain_from_pem_file(config, "cert.crt"); + quiche_config_load_priv_key_from_pem_file(config, "cert.key"); + + quiche_config_set_application_protos(config, (uint8_t *) "\x0ahq-interop\x05hq-29\x05hq-28\x05hq-27\x08http/0.9", 38); + quiche_config_set_max_idle_timeout(config, 10000); + quiche_config_set_max_recv_udp_payload_size(config, MAX_DATAGRAM_SIZE); + quiche_config_set_max_send_udp_payload_size(config, MAX_DATAGRAM_SIZE); + quiche_config_set_initial_max_data(config, 1024 * 1024 * 500); + quiche_config_set_initial_max_stream_data_bidi_local(config, 1024 * 1024 * 100); + quiche_config_set_initial_max_stream_data_bidi_remote(config, 1024 * 1024 * 100); + quiche_config_set_initial_max_streams_bidi(config, 100); + quiche_config_set_cc_algorithm(config, QUICHE_CC_RENO); + + struct sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(8889); + sa.sin_addr.s_addr = INADDR_ANY; + + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) return -1; + if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) return -1; + + int flags = fcntl(sock, F_GETFL, 0); + fcntl(sock, F_SETFL, flags | O_NONBLOCK); + + printf("QUIC Multi-Stream Server listening on port 8889\n"); + printf("Expecting approx %d MB total data...\n", TARGET_MB); + + Client *client = NULL; + uint8_t buf[65535]; + uint8_t out[MAX_DATAGRAM_SIZE]; + bool done_printing = false; + + while (1) { + struct sockaddr_storage peer_addr; + socklen_t peer_addr_len = sizeof(peer_addr); + ssize_t read_len = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&peer_addr, &peer_addr_len); + + if (read_len > 0) { + uint8_t type; + uint32_t version; + uint8_t scid[QUICHE_MAX_CONN_ID_LEN]; + size_t scid_len = sizeof(scid); + uint8_t dcid[QUICHE_MAX_CONN_ID_LEN]; + size_t dcid_len = sizeof(dcid); + uint8_t token[256]; + size_t token_len = sizeof(token); + + int rc = quiche_header_info(buf, read_len, LOCAL_CONN_ID_LEN, &version, &type, scid, &scid_len, dcid, &dcid_len, token, &token_len); + + if (rc >= 0) { + if (client == NULL) { + if (!quiche_version_is_supported(version)) { + ssize_t written = quiche_negotiate_version(scid, scid_len, dcid, dcid_len, out, sizeof(out)); + if (written > 0) sendto(sock, out, written, 0, (struct sockaddr *)&peer_addr, peer_addr_len); + } else { + client = malloc(sizeof(Client)); + client->sock = sock; + client->peer_addr = peer_addr; + client->peer_addr_len = peer_addr_len; + + uint8_t server_scid[QUICHE_MAX_CONN_ID_LEN]; + int rng = open("/dev/urandom", O_RDONLY); + read(rng, server_scid, sizeof(server_scid)); + close(rng); + + client->conn = quiche_accept(server_scid, sizeof(server_scid), dcid, dcid_len, (struct sockaddr *)&sa, sizeof(sa), (struct sockaddr *)&peer_addr, peer_addr_len, config); + client->total_bytes = 0; + client->timer_started = 0; + printf("Connection accepted.\n"); + } + } + + if (client != NULL) { + quiche_conn_recv(client->conn, buf, read_len, &(quiche_recv_info){ + .to = (struct sockaddr *)&sa, + .to_len = sizeof(sa), + .from = (struct sockaddr *)&peer_addr, + .from_len = peer_addr_len, + }); + } + } + } + + if (client != NULL) { + quiche_conn *conn = client->conn; + + if (quiche_conn_is_closed(conn)) { + printf("Connection closed.\n"); + free(client); + client = NULL; + break; + } + + if (quiche_conn_is_established(conn)) { + uint64_t s = 0; + quiche_stream_iter *readable = quiche_conn_readable(conn); + while (quiche_stream_iter_next(readable, &s)) { + if (!client->timer_started) { + clock_gettime(CLOCK_MONOTONIC, &client->start_time); + client->timer_started = 1; + } + + uint8_t recv_buf[65535]; + bool fin = false; + uint64_t err_code = 0; + ssize_t recv_bytes = quiche_conn_stream_recv(conn, s, recv_buf, sizeof(recv_buf), &fin, &err_code); + if (recv_bytes > 0) { + client->total_bytes += recv_bytes; + } + } + quiche_stream_iter_free(readable); + + // Check if target reached (fuzzy check as logic overhead might mean exact bytes vary slightly or we just use >=) + if (client->total_bytes >= (long long)TARGET_MB * 1024 * 1024 && !done_printing) { + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &end); + double time_taken = (end.tv_sec - client->start_time.tv_sec) + (end.tv_nsec - client->start_time.tv_nsec) / 1e9; + double mb = client->total_bytes / (1024.0 * 1024.0); + double throughput = mb / time_taken; + + printf("\nTest Finished:\n"); + printf("Total Data Received: %.2f MB\n", mb); + printf("Time Taken: %.2f seconds\n", time_taken); + printf("Total Throughput: %.2f MB/s\n", throughput); + done_printing = true; + } + } + + bool has_outgoing = false; + while (1) { + quiche_send_info send_info; + ssize_t written = quiche_conn_send(conn, out, sizeof(out), &send_info); + if (written == QUICHE_ERR_DONE) break; + if (written < 0) break; + sendto(sock, out, written, 0, (struct sockaddr *)&send_info.to, send_info.to_len); + has_outgoing = true; + } + + quiche_conn_on_timeout(conn); + if (!has_outgoing && !done_printing) usleep(100); + if (done_printing && !has_outgoing) usleep(10000); // Slow down if done + } + } + + quiche_config_free(config); + return 0; +} diff --git a/network/tcpquiclab/tcp_multi_client b/network/tcpquiclab/tcp_multi_client new file mode 100755 index 0000000000000000000000000000000000000000..6d6dd658a2959573d828efc7849b46d83a84f947 GIT binary patch literal 19736 zcmeHPdvF}ZneW-%(XO<5OSa_)_Q($~5A9mEY-|(3O0w)VehFKIkV`UI?~bH3(yrJY z8Ji;5V4Op^Osu1d%U#GNrV^5HKv4-vISv8w@`G|wB3x12aUnV`CQ|Hh<}RU3NYMSh zehjP0E=k=V_eW}5wf*(?_4oU_`|F)gEFqiIY9FT0j;u0}{AGNWOg(qJsY zRwY)6^>ZKjZ56P#5q)! zH!i92Csm(*UDBU!8bKa~2#*q?*BfIK{%L$fxI_A`(fdE`_^KK+UU^7#ei zs|(0)FCZT%Ah!$1{|#~jKX(|0AYc9Ia?2;DF_ce!R{{AXGf= ziwo$p!67@#2CYmconfY#wPW#H%y{1|W=|~H&-(0iD$BCz_$`*r2JOC#6-$`A(#aId zTB(F1i9>E%fMY<#$wtOD2V&4N&G?>}*^^Ag`jfX?Y`_}G!ce?Fowe9tCYiE(SUjCd zS#g^sQ$^Ug#8CCIuS?m` zoFrxrFZ+(Bs_h%&^mGkCcL;#gs@uSxXIgKZ}hEzC} zBbT=po;8*uFH_2(Z{*0;y@j&JbL6rr0u>R&4`)t2Fd`yFa{8&TG$K+YQ@$X{vIxaOS5DcSUmf9u+X#vzk0Uwq@*H_IM^5)16}loK zMdem1A?Rl!f+4vY3ncksgkn*jT9GWqMGq7`Q1n3214R$~)q3E6s^{eWSHBP)emi>LmlwLa zJDW$FPe%{8K8i+6&G=e~vETNDsutV>2pn{{wG9TMhxN5Y)?BnNf$Q#s61lEsYMh+Z z^RfO5E*^M|<5&KkFqeN69lj8K?xHvP+`HFBwG+`-KeFe+V5>A(O$I;79@T$;>*G*o zLo1>OT7#6jF*$d3d$%&(XoSHgDh{-vC^qf364x=9S?8pK@zlF@6;e&5O zgyJYCdbrC6^yfJGgec$@XdN8gM^<-8tD79FFT!;6@L|Fp;*~f~3&7~`D=7OV4&>G8 zkic38c!<&xf`N~xIB6#mvI+F*NjE0wmm<5@C+}B;%IyjB6?*#?+aU>*o%zQ zFYx|4aK3B!OHW6Khn{qG794Un#{7>HDEBzMUwDSDICz~~oaljxlbxp^V&|gK!<}P? zZafu@|1A34+uo>#s?T^A&ft}%_W``OvVdU3&xB>Vny3Q@sfN_s=b{HXPiY6fbjo+< z_fK}7A;`J8hdR$hzZyNX?xiuuh6%ud&NI+FUC=z*dKiXQkR56~_Ng)(CY-z_ruo=`HKGWgb#!J3yX z3pF>d47IEbHIv@P)NX7FC5%`ik+HJbu+b(GMk;L^*`dL~bjG$41}p0j8$@JkJ@%wX zhOmP+nUbkqV@bm3?&vb)HWIY5R~fW9CG)nl8&)jdXDsbb+p&Jq-qL<~sEl>vN#>7pA7xfi}H2HFXc@ z&;NUB>RTkokAimlcBbvA*5;P`14r;|Lvs2ifgWEkC53fnj_suL|B4*w3z;bIlbi7B3_*VX54sDECQvR%)xP{<5c|qQv{p8j9fgcR<{XdYlJ! z@;$$zY#w}wsZfH`9x(;?ei9cJqoN0j9w>UC=z*dKiXJF>py+|32Z|o}tM-8UE=_%h zM$ZTo=-W36*kBQXKeaH1%`P5}$p@a4xwn~>kRiKkb_R!h8kZleuj3bO=Z z6H=h$OJzdUdsOPFZ_!lw*l*(PK{i*#4kqU(WJ9o1%6a8yJl1jkX_^0lm~iPq&<@Emh{V#J}BuUlKx226Oz6z={u6XFR3bbFd|YLIy%-GOY!u2 zxq+7p%R|k^@@30cHa9mfXIDW(bgSr`+46h5hg4rHTatz`v~;F%<@ys4UgF&_Q~0|M zTt2wx2r@ipXVDtNUzpc`zw)Abr+(w0iJ9}<~8MHgOyPs^N|%K#MR70 z82#G$zXn%Ma$gIghS}th395b{Rkf<2!Cvz%{&uAP|pmA1M|4sDi%UkU3%=Y zH%V3wru4W@_E}&r;?kd#je~et`42#Ni!LC+TU5b3Pmyqb?N*SA3PirL1%X+x5g4G1 z#wyYU`a|OO)wY9FtfTVEKDexh)J)`-eJIPDAgw=C5#AFhC+3g!e*p1a(n<`|>Ntj# zbpy2B-1!VPo(xU{cd>oN4rEzPO81B3bLwxL7(j(+c zNKQ3mC4Lwyzpwg5q_0;}jrvYo0g+U?3CZ$1xyfCQ5>Ks!Ci78ul{|{5Vl7wtilaoW z6%DBDMSj_XS`9h=5mKN8D|v)$_i)$=2S#<1W$S2KWosoh?j6df1kciFAhYVr5Utb+ zaGEY_1pa;uRC_3cS7J3Z1yoYLcjU2sH8wbdHj?NwGE3P^p1>~e)?{vu8e@*k#W=i5l~C3 z#yIwr>8E?*<&qsW>mt%6H$Y6m?*sa(3Rz{7u|*Ft-wU%Vuw^`_ya=`TiEN(WnU{9?YA8 ziX5w}fh@h6msX}}8|w%XYy=-hM){>YqoPjpRtAHjBBW616s4~Teq2-)H{7VJ`c_Ld zQ8?+=+Z0Sr?nfx}#2c>I+K`%k}VOT&8C>w3j;y|h=a_bjZ_ zXZ?q+U)0M_>)Orw(!ghbsq63Pm7YcQx^C<9!g@uZRxjtJ-mO<`((BLaOTc+<)n}3L zdcAUh6idTg>)bVY#;VT3|cG5 z12#iQuUHNx)1+kcDxSpFN^gqo*w(Sh?AW}m^D~_t&Ow`OGKIrE1IhlqOdRORG8~%e zHF!jZr=9abHL^Im1EWeT5BsP?LE;n-FKOL|?QL7sSt2aSjE?0i+^aI9X}}&zS*^WR z%E~0;U}KqhU#mEJW;FH6w%TcGZh}!|X@`hqag2yp8Z{Y8Wzjn9$;A6&8PUk?>$Wi5 z7ULXnyOl}jw8>GY#$~O{ZedZLZ4wNyyQz#s%#Oj6)MV-EX=vWe9i2CHwRLRj?9Mr} zB&&(a?HuaqvG`Fcz7J;Fdj~C9$F`e9LZYc{w9CcMQi+nK1ZLz>DW};2xubh~CtOUv z=U!2L60_}0P8Y$X)G%=fOY}`gM;Dh0cI&pS?VB+=m>nN92Zs9Xq#5r|Vt|F>EZmnK zu)@84%d%I82Q%qiIGq*V+G*ZAv^|V7TDPS$w}gSZbtoC{kL_gPp=^c@5{7%@@i4m4 zT-DMv7?&psds9PUu`CZKQ}OmkNFvhZW zB4PD}`Y4f1gG$$s`?Fw&u#IOYWPZwSqH85ZtaOx2S~e0%%8+=@a%tAaQ15m0c*lbK zGXXa#>=V8>l}|07oYo5(o>tw@S@ghwWdS>H@PrdBLrTNbsd|o88S9ad&pS%QX&kXJ zO(GatR2!^;^+l#=!94?Sen)4w+1=K@xf6#&-6vNg>geg8Ib=$wXB}NS zoN8KP3Zd@?Xd;<*p4QQ95hrUMo{%)(O%sR%veQIjR+uK@tA%M2lg}mM;47*y{S>U3 z$fnJ{SSmp$WH)Yu7QU1)hqCzk!8w6D%^FopPKz`lo950emLl}^g;;^8DM%~}94P!I z4i!5RYNPy0W17q~actM@+`7*Eq(i!@7&?6Hz^QYloiKKCcvqkc#7t<}(=u2nyLZ6G z+!ew-UC=(2!q+EO2-8*wGanjY?`0uJv~wtlv+~IV3t{rGGJ}jO_QkS&ER@)rf>A;3 zjL6w-WwQ7nWg255FJtw`2q05~{We)dT|>6D2QeQzp-h^Oq>$BT_GDrMmf448ki*Gp zwY6_-vSYmhZ^km27%EJ7l}0gGHpNkgG%O<8?^^vo$mqQ>y<)}X&x88^4vI#kT#Zm> zEDG-W?|=+&GWR8-}=+dnMv?NU#@ zzgJYf?MA{eNZ*7v5d|YsklYEa!h6sQoPU|6JVVDPGZE z0E^Y3gID`qZ!|%Op!5XyF|Xw3kU?Wlb+dXdaQ?3kIR`k=(ekHN`FZK{0kDeLfyC|z>RM%fPa6b z0Q|-UaIx&V0{H*DTHyO!02j;XIfi8Jc5b4r9)tmPVGEY)Qc~IZbOHRaYXqQ8DHgy} zwyOxC*(%5$IWQK2rE5Tq2X+6ZeONVi1VY4W9JRQNyQ;%)v-$9kwF^5vE`W<={|nEZ BK_37B literal 0 HcmV?d00001 diff --git a/network/tcpquiclab/tcp_multi_client.c b/network/tcpquiclab/tcp_multi_client.c new file mode 100644 index 0000000..d09de10 --- /dev/null +++ b/network/tcpquiclab/tcp_multi_client.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include + +#define PORT 8081 +#define SERVER_IP "100.115.45.1" // Default IP, change if needed +#define BUFFER_SIZE 4096 +#define TOTAL_MB 100 +#define NUM_CONNS 5 +#define MB_PER_CONN (TOTAL_MB / NUM_CONNS) + +void *send_data(void *arg) { + int sock = 0; + struct sockaddr_in serv_addr; + char buffer[BUFFER_SIZE]; + memset(buffer, 'B', BUFFER_SIZE); + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("\n Socket creation error \n"); + return NULL; + } + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(PORT); + + if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) { + printf("\nInvalid address/ Address not supported \n"); + return NULL; + } + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + printf("\nConnection Failed \n"); + return NULL; + } + + long long bytes_to_send = (long long)MB_PER_CONN * 1024 * 1024; + long long bytes_sent = 0; + + while (bytes_sent < bytes_to_send) { + int to_send = (bytes_to_send - bytes_sent > BUFFER_SIZE) ? BUFFER_SIZE : (bytes_to_send - bytes_sent); + send(sock, buffer, to_send, 0); + bytes_sent += to_send; + } + + close(sock); + return NULL; +} + +int main(int argc, char const *argv[]) { + pthread_t threads[NUM_CONNS]; + printf("Starting %d TCP connections, sending %d MB each (Total %d MB).\n", NUM_CONNS, MB_PER_CONN, TOTAL_MB); + + for (int i = 0; i < NUM_CONNS; i++) { + if (pthread_create(&threads[i], NULL, send_data, NULL) != 0) { + perror("Thread create failed"); + return 1; + } + } + + for (int i = 0; i < NUM_CONNS; i++) { + pthread_join(threads[i], NULL); + } + + printf("All connections finished sending.\n"); + return 0; +} diff --git a/network/tcpquiclab/tcp_multi_server b/network/tcpquiclab/tcp_multi_server new file mode 100755 index 0000000000000000000000000000000000000000..c3d8c6223d8aa05d0e95e9992c6df3a7eeee94c1 GIT binary patch literal 22016 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 +#include +#include +#include +#include +#include +#include +#include + +#define PORT 8081 +#define BUFFER_SIZE 4096 +#define EXPECTED_CONNECTIONS 5 +#define TOTAL_TARGET_MB 100 + +long long global_bytes_received = 0; +int connections_handled = 0; +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +struct timespec start_time, end_time; +int first_connect = 1; + +void *handle_client(void *socket_desc) { + int sock = *(int*)socket_desc; + free(socket_desc); + char buffer[BUFFER_SIZE]; + int valread; + long long thread_bytes = 0; + + while ((valread = read(sock, buffer, BUFFER_SIZE)) > 0) { + thread_bytes += valread; + } + + pthread_mutex_lock(&lock); + global_bytes_received += thread_bytes; + connections_handled++; + pthread_mutex_unlock(&lock); + + close(sock); + return NULL; +} + +int main() { + int server_fd, new_socket; + struct sockaddr_in address; + int opt = 1; + int addrlen = sizeof(address); + + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("socket failed"); + exit(EXIT_FAILURE); + } + + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { + perror("setsockopt"); + exit(EXIT_FAILURE); + } + + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(PORT); + + if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("bind failed"); + exit(EXIT_FAILURE); + } + + if (listen(server_fd, 5) < 0) { + perror("listen"); + exit(EXIT_FAILURE); + } + + printf("TCP Multi-Connection Server listening on port %d...\n", PORT); + printf("Waiting for %d connections to transfer total %d MB...\n", EXPECTED_CONNECTIONS, TOTAL_TARGET_MB); + + pthread_t threads[EXPECTED_CONNECTIONS]; + int t_count = 0; + + while (t_count < EXPECTED_CONNECTIONS) { + if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + if (first_connect) { + clock_gettime(CLOCK_MONOTONIC, &start_time); + first_connect = 0; + printf("First connection received. Timer started.\n"); + } + + int *new_sock = malloc(1); + *new_sock = new_socket; + + if (pthread_create(&threads[t_count], NULL, handle_client, (void*)new_sock) < 0) { + perror("could not create thread"); + return 1; + } + t_count++; + } + + // Wait for all threads to finish + for (int i = 0; i < EXPECTED_CONNECTIONS; i++) { + pthread_join(threads[i], NULL); + } + + clock_gettime(CLOCK_MONOTONIC, &end_time); + + double time_taken = (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_nsec - start_time.tv_nsec) / 1e9; + double mb = global_bytes_received / (1024.0 * 1024.0); + double throughput = mb / time_taken; + + printf("\nTest Finished:\n"); + printf("Total Connections: %d\n", connections_handled); + printf("Total Data Received: %.2f MB\n", mb); + printf("Time Taken: %.2f seconds\n", time_taken); + printf("Total Throughput: %.2f MB/s\n", throughput); + + close(server_fd); + return 0; +}