我创建了服务器/客户端连接。服务器和客户端都可以正确编译,但是当我运行客户端时,它会给我一个Segmentation Fault (core dumped)
我不知道我的内存分配在做什么错。该程序没有悬空或任何东西。我认为我的程序正在写入内存的只读部分,或者正在访问不可用的内存。

如果有人能说出错误在哪里,我将非常感激。

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,因为一切都很好,正在等待传入连接。

谢谢!

最佳答案

这段代码有很多问题,但是直接和致命的错误是:

int bufsize = 1024;
char* buffer = new char (bufsize);
分配1个字符,并尝试将bufsize的值存储到其中。 bufsize太大,因此被截断为0。最终结果,缓冲区指向单个字符,而不是1024的数组,并且该单个值设置为0。当您尝试将bufsize字节读取到缓冲区时,几乎可以肯定超出该单个字符和behaviour is undefined的范围。它很可能会破坏其他程序数据(并可能在以后导致问题)或写入无效的内存并立即崩溃。
我相信你的意思
int bufsize = 1024;
char* buffer = new char[bufsize];
反而,
char buffer[1024];
会做你想做的。代替bufsize,使用sizeof(buffer)。此外,以下通常更可取:
在文件顶部,包括以下位置:
#define BUFSIZE 1024
接着
char buffer[BUFSIZE];
现在,您可以使用BUFSIZEsizeof(buffer)。两者都在编译过程中解决,因此没有性能成本。
2018附录:
constexpr int BUFSIZE = 1024;
在现代C++(C++ 11或更高版本)中将具有相同的效果,并且没有#define进行宏替换的不利影响。
两种选择的优点在于内存是自我管理的。 char* buffer = new char[bufsize];在代码中的某处需要delete[] buffer才能将内存放回原处。而且,您必须确保获取该delete[]才能防止泄漏。除非必须,否则不要使用指针和动态分配。
下一个,
char* ip;
strcpy(ip, "127.0.0.1");
分配未初始化的指针ip。如果包含,则包含的地址很可能由碰巧在堆栈上的任何废话组成,并且不指向有效的char数组。然后,在ip所指向的任何内容上都写上“127.0.0.1”。与更早地超过缓冲区末尾的效果类似。
同样,我们确切知道ip指向什么,因此修复很容易:
char * ip = "127.0.0.1";
我更喜欢
char ip[] = "127.0.0.1";
但我没有理由这样做。
2018附录:我现在有这样做的理由。 char * ip = "127.0.0.1";在现代C++中完全是非法的。字符串文字是常量数组,如果使用指针修改字符串文字,则将它们分配给非常量指针会导致很多弊端。在过去,我们只是忽略了问题,而从未写过字面意思。除非您稍后进行了一些抽象并且花了几天或几周的时间进行调试。最好只是从源头上解决问题,然后将文字复制到可变数组中(如果有可能会发生变异)。如果可以的话,最好在整个代码中保留const correct
接下来
recv(client, buffer, bufsize, 0);
有两个问题:
它丢弃读取的字节数和返回的错误代码。该程序不知道是否由于套接字错误而读取任何内容,或者是否获得了整个消息,消息的一部分或更多消息。
它还显示了对TCP如何工作的误解。 TCP在定义好的消息中不起作用。写入套接字的数据可以与其他消息一起打包到同一出站数据包中。它可能会拆分成多个数据包,这些数据包将在不同的时间到达。其背后的逻辑超出了StackOverflow的范围。对TCP和流数据进行一些读取。
可是等等!还有更多!
cin >> buffer;
如果用户输入1024个或更多字符,即使固定为期望的大小,也会溢出buffer(请不要忘记必须使用空终止符)。此外,您不自己计算也不知道输入了多少个字符。痛苦而缓慢。幸运的是有std::string
std::string outbuf;
cin >> outbuf;
一口气解决这两个问题。它会自行调整大小并保留其内容计数。整洁吧?
send(client, buffer, bufsize, 0);
即使用户键入的内容较少,也将发送1024字节的数据。或者更多。呸。从上方使用Outbuf,
send(client, outbuf.c_str(), outbuf.length(), 0);
每次都写入正确数量的字符,但是如果要保留字符串的终止null,则必须发送outbuf.length() + 1字符。

09-27 23:31