رفتن به مطلب
مرجع رسمی سی‌پلاس‌پلاس ایران

پست های پیشنهاد شده

باسلام

تقریبا مدت زیادی است که درگیر Socket programming  و Thread هستم. و هر چند وقت یکبار سوالاتی را در مورد چگونگی استفاده از آنها در فروم های مختلف مطرح و تا حدودی پاسخ خود را یافته ام. با توجه به اینکه گذشت زمان سوالات و شرایط تغییر کرده و لذا خواستم سوالاتی از این دست را یکبار دیگر از ابتدا مطرح و جواب کاملی برای هر کدام داشته باشم. اگر چه امکان دارد جواب هرکدام از این سوالات بطور پراکنده و جداگانه در سایتهای مختلف موجود باشد. علاوه بر آن کمتر جایی یدم که این دو موضوع را با هم بررسی کرده باشند یا فقط به مبحث Thread پرداخته اند ویا فقط درباره Socket توضیح داده اند آن هم فقط در مورد بعضی از توابع مرتبط.

حتما دوستان با ترتیب اجرای دستورات و نحوه ایجاد و مفهوم سوکتهای سمت سرور و کلاینت آشنا هستند و هفت نحوه استفاده از آنها نیست بلکه هدف این است 

اگر من بخواهم از این توابع در Thread های مختلف استفاده کنم آیا امکان پذیر است.

آیا پاسخ های داده شده برای محیط Windows, Linux, ... هردو درست است

علاوه بر کتابخانه های همراه کمپایلرها کتابخانه های دیگری نظیر Boost - Poco - ACE - Qt - ... هم کتابخانه ای برای کار با شبکه دارند وضعیت توابع مشابه در آنها چگونه است.

سوالات رو از سمت سرور شروع میکنم.

فرض لازم است سمت سرور 3 سوکت سروری داشته باشیم.

SOCKET AcceptSock1;
SOCKET AcceptSock2;
SOCKET AcceptSock3;

حال باید دستورات زیر اجرا شود

int  InitFunction(SOCKET &AcceptSock)
{
	SOCKET AcceptSock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

	if (AcceptSock == INVALID_SOCKET)
	{
		printf("Function socket failed with error : %u\n", WSAGetLastError());
		return 0;
	}

	int iTimeout = 500;
	BOOL option = TRUE;

	int iResult = setsockopt(AcceptSock, SOL_SOCKET, SO_RCVTIMEO, (char *)&iTimeout, sizeof(iTimeout));

	if (iResult == SOCKET_ERROR)
	{
		printf("Function setsockopt failed with error: %u\n", WSAGetLastError());

		return 0;
	}

	SOCKADDR_IN client_sin;
	SOCKADDR_IN local_sin;


	int iAddrSize = sizeof(client_sin);
	int iPort = 12345;

	// select the local interface, and bind to it
	local_sin.sin_addr.s_addr = htonl(INADDR_ANY);
	local_sin.sin_family = AF_INET;
	local_sin.sin_port = htons(iPort);

	if (bind(AcceptSock, (struct sockaddr *)&local_sin, sizeof(local_sin)) == SOCKET_ERROR)
	{
		printf("Function bind failed with error: %u\n", WSAGetLastError());

		return 0;
	}

	if (listen(AcceptSock, 32) == SOCKET_ERROR)
	{
		printf("Function listen failed with error: %u\n", WSAGetLastError());

		return 0;
	}
}

 فانکشن بالا باید برای AcceptSock1 و AcceptSock2 و AcceptSock3 اجرا شود. با اجرای سه کد زیر.

InitFunction(AcceptSock1);
InitFunction(AcceptSock2);
InitFunction(AcceptSock3);

سوال آیا من میتوانم هرکدام از سه دستور بالا را در Thread های مختلف اجرا کنم ویا باید حتما در Thread main اجرا شود.

برای پذیرش کلاینتهایی که درخواست اتصال دارند از تابع زیر استفاده میکنیم

int  ProcessFunction(SOCKET &AcceptSock)
{
	fd_set fd;
	timeval tv;

	SOCKADDR_IN client_sin;

	int iAddrSize = sizeof(client_sin);

	while (true)
	{
		tv.tv_sec = 3;
		tv.tv_usec = 0;

		FD_ZERO(&fd);
		FD_SET(AcceptSock, &fd);


		int iResult = select(0, &fd, NULL, NULL, &tv);
		if (iResult == SOCKET_ERROR)
		{
			printf("Function select failed with error: %u\n", WSAGetLastError());

			closesocket(AcceptSock);

			return 0;
		}

		if (iResult == 0)
		{
			continue;
		}

		SOCKET soc = accept(AcceptSock, (struct sockaddr *) &client_sin, &iAddrSize);


		if (soc == INVALID_SOCKET)
		{
			printf("Function accept failed with error: %u\n", WSAGetLastError());

			continue;
		}
		
		//... Do 

	}


}

  که باید برای AcceptSock1 و AcceptSock2 و AcceptSock3 اجرا شود. با اجرای سه کد زیر.

ProcessFunction(AcceptSock1);
ProcessFunction(AcceptSock2);
ProcessFunction(AcceptSock3);

سوال

سوال آیا من میتوانم هرکدام از سه دستور بالا را در Thread های مختلف اجرا کنم

 کلا لازم نیست هیچ گونه عملیات لاکی صورت گیرد.

آیا من میتواند از AcceptSock1 در دو Thread مختلف استفاده کنم (پاسخ خیر است فقط میخواستم جواب در اینجا باشد). اگر استفاده کنم چه اتفاقی پیش میآید.

 

فانکشن ()WSAGetLastError قطعا Threadsafe نیست ولی آیا توابع دیگری که کد خطا را بروز میکنند Threadsafe نیستند.

 

برای خواندن و نوشتن اطلاعات از Socket پذیرش شده از توابع زیر استفاده می کنیم

int SendMessageFunction   (SOCKET sock, const char * msg, int len)
{
	fd_set fd;
	timeval tv;

	tv.tv_sec = 0;
	tv.tv_usec = 0;

	FD_ZERO(&fd);
	FD_SET(sock, &fd);

	int iResult = select(0, NULL, &fd, NULL, &tv);
	
	if (iResult == SOCKET_ERROR)
	{
		printf("Function SendMessage failed with error: %u\n", WSAGetLastError());
		
		return -1;
	}
	
	int	rc = send(sock, (char *)msg, len, 0);

	if (rc != len)
	{
		return -1;
	}

	return 1;
}
int ReceiveMessageFunction(SOCKET sock,       char * msg, int &len)
{
	fd_set fd;
	timeval tv;

	tv.tv_sec = 0;
	tv.tv_usec = 0;

	FD_ZERO(&fd);
	FD_SET(sock, &fd);

	int i = select(0, &fd, NULL, NULL, &tv);
	
	if (i == SOCKET_ERROR)
	{
		printf("Function ReceiveMessage failed with error: %u\n", WSAGetLastError());

		
		return -1;
		
	}
	else if (i == 0) { // no data on socket
		return 0;
	}
	//
	//...
	//len = ...	
	//...
	int rc = recv(sock, (char *)msg, len, 0);
	// ...
	return 1;
}

 

آیا من میتوانم  تاوابع بالا را در Threadهای مختلف استفاده کنم و یا خیر.

آیا امکان خواندن از  یک سوکت توسط دو Thread مختلف امکان پذیر است. نوشتن چطور

 آیا میتوان یک Thread از Socket بخواند و Thread دیگری در آن بنویسد.

 

با توجه به این موضوع که در یکی از صفحات اینترنتی بیان شده بود که Boost برخلاف کتابخانه های دیگر Threadsafe است (اگرچه امروز هرچه گشتم دوباره آنرا پیدا نکردم)  پاسخ با توجه به پلتفورم )Windows, Linux, ..)  و کتابخانه مورد استفاده (پیشفرض کمپایلر - ACE - Poco - Boost  Qt - ...)  در نظر گرفته شود.

متشکرم

 

 

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

با تشکر از پاسخ

بطور خلاصه نتیجه گیری خودم از پاسخ های شما را اینجا می آورم لطفا اطلاح بفرمائید.

1- توابع socket - setsocketopt - bind و listen  برای استفاده در Threadها مشکلی ندارند و برای استفاده از آنها نیاز به استفاده متدهایی برای Lockکردن نیست (منظور استفاده از خود توابع بوده و فرض بر این است که پارامترها حتما مختلف خواهند بود)

2- برای استفاده از دستور accept باید از متدهای lock کردن منابع استفاده کرد حتی اگر پارامترها مختلف باشند.

3 - استفاده از توابع select - send , recv  همانند قسمت 1 هستند.

4 - اگر یک socket که بطور صحیح ایجاد و قابل استفاده است در اختیار داشته باشیم. میتوانیم در یک Thread فقط کار خواندن و در یک Thread دیگر فقط کار نوشتن روی آنرا انجام دهیم.

5- استفاده از تابع close شرایط واضح خود را دارد و حین و بعد از استفاده از آن پارامتر مشخص شده برای آن نباید در Thread دیگری مورد استفاده باشد.

6 - تابع connect عملکردی مشابه قسمت 5 دارد.

سوال 1: اگر مورد 2 صحیح باشد متوجه علت آن نمیشوم چو اگر بقیه برای استفاده در Thread مشکلی نداشته باشند این هم نباید داشته باشد ؟ 

چون بطور کلی در Thread ها مشکل استفاده از منابه مشترک است آیا توابع ذکرشده منبع حساب میشوند.

 

سوال 2: در بخش اول نپرسیدم نحوه استفاده از errno برای برسی خطا در سوکتها به چه شکل است هر Thread مقدار جداگانه ای برای خود دارد (بعید بنظر میرسد).

 

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

به گفتگو ملحق شوید

شما همین الآن می‌توانید مطلبی را ارسال و بعداً ثبت‌نام کنید. اگر حساب کاربری دارید، و با حساب کاربری خود مطلب ارسال کنید.
نکته: مطلب شما قبل از انتشار نیاز به بازبینی توسط میانجی‌گر‌ها دارد.

مهمان
ارسال پاسخ به این موضوع ...

×   شما در حال چسباندن محتوایی با قالب بندی هستید.   حذف قالب بندی

  تنها استفاده از ۷۵ اموجی مجاز می باشد.

×   لینک شما به صورت اتوماتیک جای گذاری شد.   نمایش به عنوان یک لینک به جای

×   محتوای قبلی شما بازگردانی شد.   پاک کردن محتوای ویرایشگر

×   شما مستقیما نمی توانید تصویر خود را قرار دهید. یا آن را اینجا بارگذاری کنید یا از یک URL قرار دهید.


  • کاربران آنلاین در این صفحه   0 کاربر

    هیچ کاربر عضوی،در حال مشاهده این صفحه نیست.

×
×
  • جدید...