رفتن به مطلب
جامعه‌ی برنامه‌نویسان مُدرن ایران
  • 0
kambiz behnia

Thread & Socket


سوال

باسلام

تقریبا مدت زیادی است که درگیر 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

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


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

0 پاسخ به این سوال تا کنون داده شده است

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

هنوز برای این سوال پاسخی ارسال نشده است

برای ارسال دیدگاه یک حساب کاربری ایجاد کنید یا وارد حساب خود شوید

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

ایجاد یک حساب کاربری

برای حساب کاربری جدید در سایت ما ثبت نام کنید. عضویت خیلی ساده است !

ثبت نام یک حساب کاربری جدید

ورود به حساب کاربری

دارای حساب کاربری هستید؟ از اینجا وارد شوید

ورود به حساب کاربری

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

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

×