আমার গবেষণা গ্রুপে আমরা সম্প্রতি রেড হ্যাট 6.২ থেকে ডেবিয়ান ৮.৩ এ আমাদের মেশিনগুলিতে ওএস আপগ্রেড করেছি এবং লক্ষ্য করেছি যে আমাদের মেশিনগুলির মধ্যে সংহত ইন্টেল 1 জি এনআইসি-র মাধ্যমে টিসিপি রাউন্ড ট্রিপ সময় প্রায় 110µs থেকে 220µs দ্বিগুণ হয়েছে।
প্রথমে, আমি ভেবেছিলাম এটি একটি কনফিগারেশন সমস্যা, তাই আমি সমস্ত সিস্টেমে কনফিগারেশনগুলি (যেমন tcp_low_latency=1
) আন-আপগ্রেড করা রেড হ্যাট মেশিন থেকে ডেবিয়ান মেশিনে অনুলিপি করেছিলাম এবং এটি সমস্যার সমাধান করেনি। এর পরে, আমি ভেবেছিলাম এটি লিনাক্স বিতরণ সমস্যা হতে পারে এবং মেশিনগুলিতে রেড হ্যাট 7.2 ইনস্টল করা থাকতে পারে তবে রাউন্ড ট্রিপ সময়টি প্রায় 220µ এর কাছাকাছি থেকে যায়।
অবশেষে, আমি বুঝতে পেরেছিলাম যে সমস্যাটি লিনাক্স কার্নেল সংস্করণগুলির সাথে ছিল কারণ ডেবিয়ান 8.3 এবং রেড হ্যাট 7.2 উভয়ই কার্নেল 3.x ব্যবহার করেছে যখন রেড হ্যাট 6.2 কার্নেল 2.6 ব্যবহার করেছে। সুতরাং এটি পরীক্ষা করার জন্য, আমি লিনাক্স কার্নেল ২.6 এবং বিঙ্গোর সাথে ডেবিয়ান .0.০ ইনস্টল করেছি! সময়গুলি আবার 110µs এ দ্রুত ছিল।
অন্যরাও কি লিনাক্সের সর্বশেষতম সংস্করণগুলিতে এই উচ্চতর বিলম্বকে অনুধাবন করেছে, এবং সেখানে কোনও কার্যকারিতা রয়েছে?
ন্যূনতম কাজের উদাহরণ
নীচে একটি সি ++ অ্যাপ্লিকেশন রয়েছে যা বিলম্বিতকরণের মানদণ্ডে ব্যবহার করা যেতে পারে। এটি কোনও বার্তা প্রেরণ, প্রতিক্রিয়ার অপেক্ষায় এবং তারপরে পরবর্তী বার্তা প্রেরণের মাধ্যমে বিলম্বের ব্যবস্থা করে। এটি 100-বাইট বার্তা সহ এটি 100,000 বার করে। এইভাবে, রাউন্ড ট্রিপ বিলম্ব পেতে আমরা ক্লায়েন্টের কার্যকরকরণের সময়কে 10,000,000 দিয়ে বিভক্ত করতে পারি। এই প্রথম প্রোগ্রামটি সংকলন ব্যবহার করুন:
g++ -o socketpingpong -O3 -std=c++0x Server.cpp
এর পরে একটি হোস্টে অ্যাপ্লিকেশনটির সার্ভার-পার্শ্বযুক্ত সংস্করণটি চালান (192.168.0.101 বলুন)। আমরা একটি সুপরিচিত ইন্টারফেসে হোস্টিং করছি তা নিশ্চিত করার জন্য আমরা আইপি নির্দিষ্ট করি।
socketpingpong 192.168.0.101
এবং তারপরে time
ক্লায়েন্টের কার্যকরকরণের সময়টি পরিমাপ করতে ইউনিক্স ইউটিলিটিটি ব্যবহার করুন ।
time socketpingpong 192.168.0.101 client
অভিন্ন হার্ডওয়্যার সহ দুটি ডেবিয়ান 8.3 হোস্টের মধ্যে এই পরীক্ষা চালানো নীচের ফলাফলগুলি দেয়।
real 0m22.743s
user 0m0.124s
sys 0m1.992s
দেবিয়ান 6.0 ফলাফল
real 0m11.448s
user 0m0.716s
sys 0m0.312s
কোড:
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <linux/futex.h>
#include <arpa/inet.h>
#include <algorithm>
using namespace std;
static const int PORT = 2444;
static const int COUNT = 100000;
// Message sizes are 100 bytes
static const int SEND_SIZE = 100;
static const int RESP_SIZE = 100;
void serverLoop(const char* srd_addr) {
printf("Creating server via regular sockets\r\n");
int sockfd, newsockfd;
socklen_t clilen;
char buffer[SEND_SIZE];
char bufferOut[RESP_SIZE];
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
perror("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(srd_addr);
serv_addr.sin_port = htons(PORT);
fflush(stdout);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
}
listen(sockfd, INT_MAX);
clilen = sizeof(cli_addr);
printf("Started listening on %s port %d\r\n", srd_addr, PORT);
fflush(stdout);
while (true) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
perror("ERROR on accept");
printf("New connection\r\n");
int status = 1;
while (status > 0) {
// Read
status = read(newsockfd, buffer, SEND_SIZE);
if (status < 0) {
perror("read");
break;
}
if (status == 0) {
printf("connection closed");
break;
}
// Respond
status = write(newsockfd, bufferOut, RESP_SIZE);
if (status < 0) {
perror("write");
break;
}
}
close(newsockfd);
}
close(sockfd);
}
int clientLoop(const char* srd_addr) {
// This example is copied from http://www.binarytides.com/server-client-example-c-sockets-linux/
int sock;
struct sockaddr_in server;
char message[SEND_SIZE] , server_reply[RESP_SIZE];
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket");
}
puts("Socket created");
server.sin_addr.s_addr = inet_addr(srd_addr);
server.sin_family = AF_INET;
server.sin_port = htons( PORT );
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("connect failed. Error");
return 1;
}
printf("Connected to %s on port %d\n", srd_addr, PORT);
// Fill buffer
for (int i = 0; i < SEND_SIZE; ++i) {
message[i] = 'a' + (i % 26);
}
for (int i = 0; i < COUNT; ++i) {
if (send(sock, message, SEND_SIZE, 0) < 0) {
perror("send");
return 1;
}
if ( recv(sock, server_reply, RESP_SIZE, 0) < 0) {
perror("recv");
return 1;
}
}
close(sock);
printf("Sending %d messages of size %d bytes with response sizes of %d bytes\r\n",
COUNT, SEND_SIZE, RESP_SIZE);
return 0;
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("\r\nUsage: socketpingpong <ipaddress> [client]\r\n");
exit(-1);
}
if (argc == 2)
serverLoop(argv[1]);
else
clientLoop(argv[1]);
return 0;
}