Задать вопрос

Отправка данных с сервера к клиенту по 1 сокету.C++

Доброго времени суток.Нужно сделать чат на c++,я сделал половину работы и клиент отправляет данные серверу,все нормально,думал что бы отправить данные с сервера на клиент сделать просто все обратно(то есть на клиенте поместить прослушивание recv от сервера,а на сервере сделать send) по этому же сокету,но что-то ничего не получается.Что подскажут гуру?Как лучше сделать?(TCP соединение)
Хотел спросить,может все таки надо создавать еще один сокет с теми же параметрами что бы отправлять данные к клиенту,или как лучше сделать?
вот код сервера
private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
				 button3->Enabled = "true";
				 timer1->Enabled = true;
				 timer = "True";
				 //--- INITIALIZATION -----------------------------------
				 wVersionRequested = MAKEWORD(1, 1);
				 err = WSAStartup(wVersionRequested, &wsaData);

				 if (err != 0) {
					 textBox1->Text = "WSAStartup error :" + System::Convert::ToString(WSAGetLastError());
					 WSACleanup();
					 timer = false;
				 }


				 //------------------------------------------------------



				 //---- Build address structure to bind to socket.--------  
				 memset(&channel, 0, sizeof(channel));// zerochannel 
				 channel.sin_family = AF_INET;
				 channel.sin_addr.s_addr = htonl(INADDR_ANY);
				 channel.sin_port = htons(SERVER_PORT);
				 //--------------------------------------------------------


				 // ---- create SOCKET--------------------------------------
				 s = socket(PF_INET,  SOCK_STREAM, IPPROTO_TCP);
				 if (s < 0) {
					 textBox1->Text = "socket error :" + System::Convert::ToString(WSAGetLastError());
					 WSACleanup();
					 timer = false;
				 }

				 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
				 //---------------------------------------------------------

				 //---- BIND socket ----------------------------------------
				 b = bind(s, (struct sockaddr *) &channel, sizeof(channel));
				 if (b < 0) {
					 textBox1->Text = "bind error :" + System::Convert::ToString(WSAGetLastError());
					 WSACleanup();
					 timer = false;
				 }
				 //----------------------------------------------------------

				 //---- LISTEN socket ----------------------------------------
				 l = listen(s, QUEUE_SIZE);                 // specify queue size 
				 if (l < 0) {

					 textBox1->Text = "listen error %ld" + System::Convert::ToString(WSAGetLastError());
					 WSACleanup();
					 timer = false;
				 }

				 //-----------------------------------------------------------


				 //---- ACCEPT connection ------------------------------------

				 sa = accept(s, 0, 0);                  // block for connection request  
				 if (sa < 0) {

					 textBox1->Text = "accept error " + System::Convert::ToString(WSAGetLastError());
					 WSACleanup();
					 timer = false;
				 }
				 else {

					 textBox1->Text = "connection accepted";
				 }
				 //------------------------------------------------------------
			
				 

	}
	private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
				 timer = false;
				 closesocket(s);
				 closesocket(sa);
				 WSACleanup();
				 timer1->Enabled = FALSE;
	}
	private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
				// ---- RECV bytes --------------------------------------------

				
							unsigned long mode = 1;
							ioctlsocket(sa, FIONBIO, &mode);
							bytesRecv = recv(sa, recvbuf, 50, 0);
							 err = WSAGetLastError();// 10057 = A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) 
							 if (bytesRecv == 0 || bytesRecv == WSAECONNRESET) {

								 textBox1->Text = "Connection Closed.\n";
								 WSACleanup();
							 }
							 else{

								 textBox1->Text = gcnew String(recvbuf);

							 }
					
	}
	private: System::Void button3_Click(System::Object^  sender, System::EventArgs^  e) {
				 char buf[50] = "";
				 int bytesSent;
				 if (timer == true) {
					 String ^ strT;
					 strT = textBox2->Text;
					 int TempNumOne = textBox2->Text->Length;
					 for (int a = 0; a < TempNumOne; a++)
					 {

						 buf[a] = strT[a];

					 }
				 bytesSent = send(s, buf, 50, 0);
					 
					 textBox1->Text = "Sent:" + System::Convert::ToString(bytesSent);
					 textBox1->Text = "Message :" + textBox2->Text; }
				 }
	}
  • Вопрос задан
  • 4703 просмотра
Подписаться 3 Оценить Комментировать
Пригласить эксперта
Ответы на вопрос 1
@WhoMe
Не гуру, но вставлю свои 5 копеек.

Общий принцип работы (для блокирующихся сокетов)
Клиент (тут все просто):
- Создаем сокет (ClientSocket)
- Конектимся к серверу
- Пишем/читаем в/из ClientSocket

Сервер:
- Создаем сокет (ListenSocket)
- Вызываем accept (поток блокируется пока не подключится клиент или не произойдет ошибка)
- Accept возвращает сокет (ClientSocket), он ассоциириован с нашим подключившимся клиентом.
Если мы хотим отправить/прочитать данные в/из этому клиенту, то читаем/пишем из/в ClientSocket.
- Если мы хотим "принять" еще одного клиента, то снова вызыаем Accept

Еще раз. Если у нас к серверу подключены, скажем, 5 клиентов. То у нас получается 6 сокетов: 1 слушающий + 5 клиентов.

Будет не лишним отметить некоторые особенности при работе с блокирующимися сокетами.

Возьмем к примеру клиентскую часть.
Вы нажимаете кнопку в интерфейсе, вызывается функция, например button1_Click.
Создается socket и вызывается функция connect. В этом месте поток блокируется пока сокет не соединится или не произойдет ошибка.
(Аналогично с accept в серверной части) Т.е Ваша программа визуально "подвиснет". Интерфейс перестанет реагировать. То же касается чтения и записи.
Решением может быть создание отдельных потоков для работы с сокетами, либо использование мультиплексированного ввода/вывода.

По вашему коду:
1.
send(s, buf, 50, 0);
Отправляете данные не в тот сокет. Надо в sa. (См. sa = accept(s, 0, 0); // block for connection request)

2.
ioctlsocket(sa, FIONBIO, &mode);
bytesRecv = recv(sa, recvbuf, 50, 0);
err = WSAGetLastError();// 10057 = A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) 
if (bytesRecv == 0 || bytesRecv == WSAECONNRESET) {

Т.к вы переключили сокет в неблокируйщися режим возвращение нуля тут штатная ситуация. Также обратите внимание на bytesRecv == WSAECONNRESET, сравнение явно не с той переменной.

См. также
habrahabr.ru/post/111357
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы