2015-07-10 4 views
1

Я создал соединение сервер/клиент. Сервер и клиент оба компилируются правильно, но когда я запускаю клиент, он дает мне Segmentation Fault (core dumped)C++ Sockets - Клиент дает ошибку сегментации (linux)

Я не знаю, что я делаю неправильно с распределением памяти. Программа не болтается или что-то еще. Я думаю, что моя программа записывает часть памяти только для чтения или может получить доступ к памяти, которая недоступна.

Если кто-нибудь может сказать, где ошибка, я бы очень признателен.

client.cpp

#include <iostream> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 
#include <stdlib.h> 
#include <unistd.h> 
using namespace std; 

int main() { 
    char a; 
    int client; 
    int portNum = 1500; 
    int bufsize = 1024; 
    char* buffer = new char (bufsize); 
    bool isExit = false; 
    char* ip; 
    strcpy(ip, "127.0.0.1"); 

struct sockaddr_in direc; 

if ((client = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 
    cout << "Error creating socket..." << endl; 
    exit(0); 
} 

cout << "Enter # to end call" << endl; 
cout << "\t\t\t[s] to begin with" << endl; 
cin >> a; 

cout << "Socket created successfully..." << endl; 
direc.sin_family = AF_INET; 
direc.sin_port = htons(portNum); 
inet_pton(AF_INET, ip, &direc.sin_addr); 

if (connect(client,(struct sockaddr *)&direc, sizeof(direc)) == 0) 
    cout << "Connection to the server " << inet_ntoa(direc.sin_addr) << endl; 

cout << "Awaiting confirmation from the server..." << endl; 
recv(client, buffer, bufsize, 0); 

cout << "Response received: " << buffer; 
cout << "\nRemember to put an asterisk at the end to send a message * \n Enter # to terminate the connection" << endl; 

do { 
    cout << "Enter a message: "; 
    do { 
     cin >> buffer; 
     send(client, buffer, bufsize, 0); 
     if (*buffer == '#') { 
      send(client, buffer, bufsize, 0); 
      *buffer = '*'; 
      isExit = true; 
     } 
    } while (*buffer != 42); 

    cout << "Mensage received: "; 
    do { 
     recv(client, buffer, bufsize, 0); 
     cout << buffer << " "; 
     if (*buffer == '#') { 
      *buffer = '*'; 
      isExit = true; 
     } 

    } while (*buffer != 42); 
    cout << endl; 

} while (!isExit); 
cout << "Connection terminated. END PROGRAM\n\n"; 
close(client); 
return 0; 
} 

Я предполагаю, что вы не нуждаетесь в server.cpp, так как это все хорошо и ждет входящих соединений.

Спасибо!

+2

'char * ip; strcpy (ip, "127.0.0.1"); 'Никогда не выделял никакого хранилища для указателя, на который он указывает, никогда не указывал его ни на что, а затем копировал данные в этот неопределенный регион. KABOOOM! – user4581301

+0

... и 'char * buffer = new char (bufsize);' не то, что вы думаете ('() []'). И у вас точно 0 'delete []'. ... «Я не знаю, что я делаю неправильно с распределением памяти». Все. В любом месте нет правильного распределения. – deviantfan

+0

Почему бы просто не написать 'char * ip =" 127.0.0.1 ";' – Barmar

ответ

5

Есть целый ряд проблем, связанных с этим кодом, но непосредственные и фатальные ошибки:

int bufsize = 1024; 
char* buffer = new char (bufsize); 

Распределяет 1 персонаж и пытается BUFSIZE в него. Bufsize слишком велик, поэтому он обрезается до 0. Конечный результат, буфер указывает на один символ, а не на массив 1024, а одно значение равно 0. Когда вы пытаетесь прочитать байты bufsize в буфер, вы почти наверняка переполняете этот одиночный символ и либо уничтожить некоторые другие данные программы (и позже сбой), либо записать в недействительную память и немедленно сработать.

Я считаю, что вы имели в виду

int bufsize = 1024; 
char* buffer = new char[bufsize]; 

Вместо,

char buffer[1024]; 

будет делать то, что вы хотите. Вместо bufsize используйте sizeof(buffer). Кроме перечисленного часто предпочтительнее:

вверх в верхней части файла, прямо под включает в себя:

#define BUFSIZE 1024 

и затем

char buffer[BUFSIZE]; 

Теперь вы можете использовать BUFSIZE или sizeof(buffer). Обе версии разрешены во время компиляции, поэтому затраты на производительность отсутствуют.

Красота обоих вариантов - память управляется самостоятельно. char* buffer = new char[bufsize]; требует delete[] buffer где-то в вашем коде, чтобы вернуть память. И вы должны убедиться, что добрались до этого delete[]. Не используйте указатели и динамическое распределение, если это необходимо.

Далее

char* ip; 
strcpy(ip, "127.0.0.1"); 

выделяет указатель, ip, который указывает на то, что дерьмо случилось быть в стеке. Затем «127.0.0.1» записывается поверх того, на что указывалось ip. Тот же эффект, что и предыдущий конец буфера.

Опять же, мы знаем точно, что ф будет указывать на, так что исправление легко:

char * ip = "127.0.0.1"; 

Я предпочитаю

char ip[] = "127.0.0.1"; 

но у меня нет никаких оснований для этого.

Далее,

recv(client, buffer, bufsize, 0); 

Имеет две проблемы:

отбрасывается количество прочитанных байтов и коды ошибок возвращаются. Программа не имеет понятия, прочитает ли она что-либо вообще из-за ошибки сокета или если он получил все сообщение.

Он также демонстрирует непонимание того, как работает TCP. TCP не работает в славных, определенных пакетах. Данные, записанные в сокет, могут быть упакованы в одно и то же сообщение с другими данными. Он может быть разделен на несколько пакетов и поступать в разное время. Логика, лежащая в основе этого, выходит за рамки StackOverflow. Прочитайте некоторые данные по TCP и потоковым данным.

Но подождите! Больше!

cin >> buffer; 

переполнится buffer даже если прикреплено к ожидаемому размеру, если пользователь в 1025 или более символов. Кроме того, вы не знаете, сколько символов было введено, не считая их самостоятельно. Болезненный и медленный. К счастью, существует std :: string.

std::string outbuf; 
cin >> outbuf; 

Решает обе проблемы одним выстрелом. Он изменяет размеры и сохраняет количество содержимого. Аккуратно, да?

send(client, buffer, bufsize, 0); 

Отправляет 1024 байта данных, даже если пользователь набрал меньше. Или больше. Тьфу. Использование OutBuf сверху,

send(client, outbuf.c_str(), outbuf.length(), 0); 

Пишет правильное число символов каждый раз, но если вы хотите сохранить завершающего нуль струны, вы должны отправить outbuf.length() + 1 символов.

+0

Вау, это то, что я называю подробным и исчерпывающим ответом. +1, полностью заслуженно! –

Смежные вопросы