[英]C++ Sockets - Client gives segmentation fault (linux)
我創建了一個服務器/客戶端連接。 服務器和客戶端都正確編譯,但是當我運行客戶端時,它給了我一個Segmentation Fault (core dumped)
我不知道我的內存分配做錯了什么。 該程序沒有懸空或任何東西。 我認為我的程序正在寫入內存的只讀部分,或者可能訪問不可用的內存。
如果有人能告訴我錯誤在哪里,我將不勝感激。
客戶端
#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
字節讀入緩沖區時,您幾乎可以肯定超出該單個字符並且行為未定義。 它很可能會破壞一些其他程序數據(並且可能會在以后引起問題)或寫入無效內存並立即崩潰。
我相信你的意思
int bufsize = 1024;
char* buffer = new char[bufsize];
反而,
char buffer[1024];
會做你想做的。 使用sizeof(buffer)
代替bufsize
。 此外,以下通常更可取:
在文件的頂部,就在包含的下面:
#define BUFSIZE 1024
進而
char buffer[BUFSIZE];
現在您可以使用BUFSIZE
或sizeof(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
。 最有可能的地址 if contains 由堆棧上的任何垃圾組成,並且不指向有效的char
數組。 然后“127.0.0.1”被寫入ip
所指向的任何內容。 與之前溢出緩沖區末尾的效果類似。
同樣,我們確切地知道ip
將指向什么,因此修復很容易:
char * ip = "127.0.0.1";
我更喜歡
char ip[] = "127.0.0.1";
但我沒有理由這樣做。
2018 年附錄:我現在有這樣做的理由。 char * ip = "127.0.0.1";
在現代 C++ 中是完全非法的。 字符串文字是常量數組,如果使用指針修改字符串文字,將它們分配給非常量指針會導致很多壞處。 在過去,我們只是忽略了這個問題,從來沒有寫過文字。 除非您稍后進行了一些抽象並花費了數天或數周的時間進行調試。 如果有可能發生變異,最好從源頭上解決問題並將文字復制到可變數組中。 如果可以的話,更好的是在整個代碼中保持const 正確。
接下來,
recv(client, buffer, bufsize, 0);
有兩個問題:
它丟棄讀取的字節數和返回的錯誤代碼。 程序不知道它是否因為套接字錯誤而讀取任何內容,或者它是否獲得了整個消息、部分消息或更多消息。
這也說明了對 TCP 工作原理的誤解。 TCP 在良好的、定義的消息中不起作用。 寫入套接字的數據可能與其他消息打包到同一個出站數據包中。 它可能會被分成多個在不同時間到達的數據包。 這背后的邏輯超出了 StackOverflow 的范圍。 閱讀 TCP 和流數據。
可是等等! 還有更多!
cin >> buffer;
如果用戶輸入 1024 個或更多字符(不要忘記需要空終止符),即使將buffer
固定為預期大小,也會溢出buffer
。 此外,您不知道輸入了多少字符而不自己計算它們。 痛苦而緩慢。 幸運的是有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
字符。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.