Не гуру, но вставлю свои 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