C++套接字 - 客户端给出分段错误(linux)

has*_*nyf 1 c++ sockets linux memory

我创建了一个服务器/客户端连接.服务器和客户端都正在正确编译,但是当我运行客户端时,它给了我一个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;
}
Run Code Online (Sandbox Code Playgroud)

我假设你不需要server.cpp,因为它一切都很好,等待传入的连接.

谢谢!

use*_*301 9

此代码存在许多问题,但直接和致命的错误是:

int bufsize = 1024;
char* buffer = new char (bufsize);
Run Code Online (Sandbox Code Playgroud)

分配1个字符并尝试将bufsize放入其中.Bufsize太大,因此被截断为0.最终结果,缓冲区指向单个字符,而不是1024的数组,并且该单个值设置为0.当您尝试将bufsize字节读入缓冲区时,几乎肯定会溢出单个字符并破坏其他程序数据(以后会导致问题)或写入无效内存并立即崩溃.

我相信你的意思

int bufsize = 1024;
char* buffer = new char[bufsize];
Run Code Online (Sandbox Code Playgroud)

代替,

char buffer[1024]; 
Run Code Online (Sandbox Code Playgroud)

会做你想做的.而不是bufsize,使用sizeof(buffer).此外,以下通常更可取:

在文件的顶部,在包含的正下方:

#define BUFSIZE 1024
Run Code Online (Sandbox Code Playgroud)

然后

char buffer[BUFSIZE]; 
Run Code Online (Sandbox Code Playgroud)

现在你可以使用BUFSIZEsizeof(buffer).两者都在编译期间解析,因此没有性能成本.

2018年附录:

constexpr int BUFSIZE = 1024;
Run Code Online (Sandbox Code Playgroud)

将在现代C++(C++ 11或更新版本)中具有相同的效果,并且没有宏的替代的缺点#define.

两种选择的美妙之处在于记忆是自我管理的.char* buffer = new char[bufsize];需要delete[] buffer在代码中的某处将内存放回原处.你必须确保你达到这个目标delete[].除非必须,否则不要使用指针和动态分配.

下一个,

char* ip;
strcpy(ip, "127.0.0.1");
Run Code Online (Sandbox Code Playgroud)

分配一个指针,ip指向堆栈上发生的任何垃圾.然后将"127.0.0.1"写入所发生的任何事情ip.与先前超出缓冲区末尾的效果相同.

同样,我们确切知道ip将指向什么,因此修复很容易:

char * ip = "127.0.0.1";
Run Code Online (Sandbox Code Playgroud)

我更喜欢

char ip[] = "127.0.0.1";
Run Code Online (Sandbox Code Playgroud)

但我没有理由这样做.

2018年附录:我现在有理由这样做.char * ip = "127.0.0.1";在现代C++中是完全违法的.字符串文字是常量数组,如果指针用于修改字符串文字,则将它们分配给非常量指针会导致很多不良.在过去,我们只是忽略了这个问题,从未写过文字.除非您稍后进行了一些抽象,并花了数天或数周的时间进行调试.最好只是在源头上解决问题并将文字复制到一个可变数组,如果它有可能被突变的话.如果可以的话,更好的是在整个代码中保持const正确.

接下来,

recv(client, buffer, bufsize, 0);
Run Code Online (Sandbox Code Playgroud)

有两个问题:

它会丢弃读取的字节数和返回的错误代码.由于套接字错误或是否收到整个消息,程序根本不知道它是否读取任何内容.

它还表明了对TCP如何工作的误解.TCP不适用于定义良好的数据包.写入套接字的数据可以与其他数据一起打包到相同的出站消息中.它可以分成多个数据包并在不同时间到达.这背后的逻辑超出了StackOverflow的范围.做一些关于TCP和流数据的阅读.

可是等等!还有更多!

cin >> buffer;
Run Code Online (Sandbox Code Playgroud)

buffer如果用户键入1025或更多字符,即使固定为预期大小,也会溢出.此外,您不知道输入了多少字符而不自己计算.痛苦而缓慢.幸运的是有std::string.

std::string outbuf;
cin >> outbuf;
Run Code Online (Sandbox Code Playgroud)

一次解决两个问题.它调整自身的大小并保持其内容的计数.整洁,对吧?

send(client, buffer, bufsize, 0);
Run Code Online (Sandbox Code Playgroud)

即使用户键入较少,也会发送1024字节的数据.或者更多.呸.使用上面的outbuf,

send(client, outbuf.c_str(), outbuf.length(), 0);
Run Code Online (Sandbox Code Playgroud)

每次写入正确的字符数,但如果要保留字符串的终止null,则必须发送outbuf.length() + 1字符.

  • 哇,这就是我所说的详细而详尽的答案。+1,当之无愧! (2认同)