Приложение C ++ mini chat

0

поэтому я пытаюсь создать приложение для мини-чата, просто для того, чтобы понять и спроектировать программирование сокетов, а также кое-что о потоках, я делаю это с помощью c++ Mfc, я могу установить соединение между клиентом и сервером (проверено это с помощью netstat), но что касается функций send и recv, я не могу понять, как это должно быть сделано, я отправляю сообщение из клиентского приложения, но сервер, похоже, не получает его

Исходный код сервера:

int RcvThread();
SOCKET s;
void CChat_ServerDlg::OnBnClickedButton2()
{

WSADATA w;

int error = WSAStartup ( 0x0202,&w);
if(error)
{
    OnCancel();
}
 if (w.wVersion != 0x0202) 
{
    WSACleanup ();
    OnCancel();
}
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(DEFAULT_PORT);
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
s = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP);
     if (s == INVALID_SOCKET)
{
    OnCancel();
}
 if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
{

    OnCancel();
}
listen (s, SOMAXCONN);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE) RcvThread, NULL, NULL, NULL);

int buffsize = 1024;
char msg[1024] = "a";
int marker;
}

    int RcvThread()
    {
char sbuffer[256];

char buffer[sizeof(sbuffer)] = {0};

for(;; )
{

    if(recv(s, buffer, sizeof(sbuffer), NULL) > 0)
    {
        memcpy(&sbuffer, buffer, sizeof(sbuffer));
        MessageBox(hnd,sbuffer,"message",NULL);
    }
}

return 0;
    }

Исходный код клиента:

SOCKET s;
void CChat_ClientDlg::OnBnClickedOk()
{

WSADATA wsadata;

int error = WSAStartup(0x0202,&wsadata);

 if (error)
{
    MessageBox("Error","ERRR");

    OnCancel();
}


if (wsadata.wVersion != 0x0202) 
{
    WSACleanup ();
    OnCancel();
}

SOCKADDR_IN target;

target.sin_family = AF_INET;
target.sin_port = htons(3124);
target.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

s = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (s == INVALID_SOCKET)
{
    OnCancel();
}

   if (connect(s, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR)
{
    OnCancel();
}
}

сообщение отправки кнопки:

void CChat_ClientDlg::OnBnClickedButton2()
{
char* Msg = new char[256];
Msg = "abdouabdouabdou";
send(s,Msg,256,NULL);
}
  • 0
    Поскольку этот вопрос помечен как MFC, удивительно, что вы не используете класс CSocket .
Теги:
sockets
mfc
chat

2 ответа

1

Вам не хватает фундаментальной концепции сокетов. Слуховой сокет (s в вашем коде) используется для приема запросов на соединение. Он не используется для отправки/получения данных. Для этого вам нужно создать другой сокет. Вам нужно больше изучить документацию и образцы. Один из источников:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms738545(v=vs.85).aspx

Кроме того, ваша резьба неправильна. Функция потока должна соответствовать сигнатуре, указанной для CreateThread, если вы используете CreateThread. Но в приложении MFC вы должны использовать AfxBeginThread вместо CreateThread.

  • 0
    Прежде всего, спасибо, что при использовании функции recv я прочитал этот файл msdn.microsoft.com/en-us/library/windows/desktop/… поэтому я предположил, что сокет прослушивания можно использовать для получения и отправки данных, я увидел другие программы, которые использовали два сокета, но я почему-то проигнорировал это, к тому же я все еще не привык работать с msdn, для меня это не достаточно линейно
  • 0
    MSDN - справочный материал: не самый лучший для изучения концепций. Один хороший урок по winsock можно найти в FAQ программиста winsock.
0

Прежде всего, полагая, что send() и recv() будут отправлять и получать пакеты, это распространенное заблуждение. Если вы используете TCP (что необходимо для программы чата), recv() может возвращать любое количество байт между 0 и указанным вами ограничением буфера. Поэтому, если вы отправляете 256 байтов, ваша функция recv() может разбить это на два, три или более фрагмента сообщения или может вернуть конец первого сообщения вместе с началом второго. Часто делается то, что первый n-байт сообщения (n зависит от того, какой ваш максимальный размер сообщения) обозначает длину сообщения. Поскольку вы ограничиваете свой протокол длиной до 256 байтов, достаточно 1 байт. После получения первого байта выделите буфер сообщений размером с ваше сообщение и поместите recv() в цикл... well... receive, пока он не получит все сообщение. Вам нужно жонглировать бит смещениями в буфер приема и т.п.

Во-вторых, вы не совсем поняли, как работает система bind()/listen()/accept(). Функция listen() устанавливает сокет в пассивный режим, в котором он прослушивает новых клиентов. accept(), наконец, устанавливает соединение с новым клиентом и возвращает новый сокет, который затем используется для связи с клиентом. Оригинальный (прослушивающий) сокет продолжает прослушивание новых клиентов.

В-третьих, ваша функция отправки неправильно обрабатывает ваши char-buffers. Я немного поправил его в отношении моего предложения (первый байт сообщений отмечает длину следующего сообщения):

void CChat_ClientDlg::OnBnClickedButton2()
{
  std::string myMessage = "abdouabdouabdou";
  unsigned char buffer[256];
  buffer[0] = (unsigned char)myMessage.length();
  memcpy(buffer+1, myMessage.c_str(), std::min(myMessage.length(), 255));
  send(s, buffer, 256, NULL);
}

Даже этот метод неверен, потому что send() возвращает количество отправленных байтов, которое может быть меньше размера моего буфера, хотя это редкий случай для таких небольших сообщений.

  • 0
    : / Да, я совершенно не хочу заниматься такими проектами без достаточного фона, сегодня днем я буду больше читать и смотреть пару подробных уроков, спасибо

Ещё вопросы

Сообщество Overcoder
Наверх
Меню