我正在处理这个 HOMEWORK 任务,并且此时花了很多时间。我已经能够让我的Mac完美地运行客户端和服务器但是要求说它必须在Linux机器上运行,这是我发现它的主要问题。我在客户端连接到服务器后立即收到分段错误,它发生在两条cout线之间,这对我来说毫无意义。我花了大约4个小时来研究这个时间没有运气。有人能给我任何有用的指示吗?提前谢谢!
Server.cpp
//header files
//input - output declarations included in all C programs
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <vector>
#include <string>
#include <stdexcept>
#include <iostream>
//contains definitions of a number of data types used in system calls
#include <sys/types.h>
//definitions of structures needed for sockets
#include <sys/socket.h>
//in.h contains constants and structures needed for internet domain addresses
#include <netinet/in.h>
using namespace std;
int* clientNumbers = new int[50];
void initializeArray()
{
for(int i = 0; i < 50; i++)
{
clientNumbers[i] = 0;
}
}
//This function is called when a system call fails. It displays a message about the error on stderr and then aborts the program.
void error(const char *msg)
{
perror(msg);
exit(1);
}
int numberClients = 0;
bool checkNumber(int number)
{
for(int i = 0; i < 50; i++)
{
if(number == clientNumbers[i])
{
return false;
}
}
clientNumbers[numberClients] = number;
numberClients++;
return true;
}
int main(int argc, char *argv[]){
pid_t childPID;
initializeArray();
//sockfd and newsockfd are file descriptors,These two variables store the values returned by the socket system call and the accept system call.
//portno stores the port number on which the server accepts connections.
int sockfd, newsockfd, portno;
//clilen stores the size of the address of the client. This is required for the accept system call.
socklen_t clilen;
//serv_addr will contain the address of the server, and cli_addr will contain the address of the client which connects to the server.
struct sockaddr_in serv_addr, cli_addr;
int n;
//create socket
//it take three arguments - address domain, type of socket, protocol (zero allows the OS to choose thye appropriate protocols based on type of socket)
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
string portNumber;
cout << "Please Enter Port Number:";
getline(cin, portNumber);
//stoi() function can be used to convert port number from a string of digits to an integer, if your input is in the form of a string.
try{
portno = stoi(portNumber);
}catch(const std::invalid_argument e)
{
error("ERROR No Port Number Entered.");
}
if(portno > 65535 || portno < 1)
{
error("Invalid Port Number. Exiting.");
}
//contains a code for the address family
serv_addr.sin_family = AF_INET;
//contains the IP address of the host
serv_addr.sin_addr.s_addr = INADDR_ANY;
//contain the port number
serv_addr.sin_port = htons(portno);
//bind() system call binds a socket to an address, in this case the address of the current host and port number on which the server will run.
//three arguments, the socket file descriptor, the address to which is bound, and the size of the address to which it is bound.
if (::bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
//listen system call allows the process to listen on the socket for connections.
//The first argument is the socket file descriptor, and second is number of connections that can be waiting while the process is handling a particular connection.
listen(sockfd,5);
while(1)
{
cout << "Server waiting...\n";
//This is where the program experiences a Segmentation Fault
cout << "Just Before Clilen";
clilen = (socklen_t) sizeof(cli_addr);
//accept() system call causes the process to block until a client connects to the server.
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
cout << "WE MADE IT THIS FAR!";
if (newsockfd < 0)
error("ERROR on accept");
string clientNumberString;
int clientNumber = 0;
n = read(newsockfd,&clientNumberString,15);
if (n < 0) error("ERROR reading from socket\n");
clientNumber = stoi(clientNumberString);
if(checkNumber(clientNumber)) {
//reads from the socket into a buffer for a maximum of 255 characters
//read call uses new file descriptor, the one returned by accept()
if(fork() == 0)
{
cout << "Established Connection With: " << clientNumber << "\n";
while(1)
{
string lowerCase;
//Read in String from Client
n = read(newsockfd, &lowerCase, 255);
if(n == 0)break;
//transform(lowerCase.begin(), lowerCase.end(), lowerCase.begin(), ::toupper);
string upperCase = "";
for(int i = 0; i < lowerCase.length(); i++)
{
upperCase += toupper(lowerCase.at(i));
}
n = write(newsockfd, &upperCase, upperCase.length() + 1);
}
cout << "Disconnecting from Client\n";
//close connections using file descriptors
close(newsockfd);
}
}else
{
n = write(newsockfd, 0, 1);
cout << "CONNECTION REFUSED: Client Number already Taken.\n";
break;
}
}
//
close(sockfd);
return 0;
}
运行输出示例:
./server
Please Enter Port Number:6666
Server waiting...
Segmentation fault (core dumped)
GDB的Backtrace:
Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (
nptr=0x2388058 <error: Cannot access memory at address 0x2388058>,
endptr=0x7fffffffde00, base=10, group=<optimized out>,
loc=0x7ffff78ba060 <_nl_global_locale>) at ../stdlib/strtol_l.c:298
298 ../stdlib/strtol_l.c: No such file or directory.
(gdb) backtrace
#0 __GI_____strtol_l_internal (
nptr=0x2388058 <error: Cannot access memory at address 0x2388058>,
endptr=0x7fffffffde00, base=10, group=<optimized out>,
loc=0x7ffff78ba060 <_nl_global_locale>) at ../stdlib/strtol_l.c:298
#1 0x0000000000401ca1 in __gnu_cxx::__stoa<long, int, char, int> (
__convf=0x401350 <strtol@plt>, __name=0x401da9 "stoi",
__str=0x2388058 <error: Cannot access memory at address 0x2388058>,
__idx=0x0) at /usr/include/c++/4.8/ext/string_conversions.h:62
#2 0x0000000000401bab in std::stoi (__str=..., __idx=0x0, __base=10)
at /usr/include/c++/4.8/bits/basic_string.h:2825
#3 0x00000000004017fd in main (argc=1, argv=0x7fffffffdfe8) at main.cpp:143
答案 0 :(得分:4)
dict1 = {1:2,3:4,5:6}
dict2 = {1:7}
dict(dict1.items() + dict2.items())
通过阅读顶部的数据,您可以在此处删除字符串。 string clientNumberString;
int clientNumber = 0;
n = read(newsockfd,&clientNumberString,15);
不仅仅是一个字符数组,它是一个包含指针,长度和可能的其他信息的结构。你不能只在其地址写任意数据,并期望它能够发挥作用。
此外,您似乎对TCP的工作原理有一些基本的误解:
string
在第一行之后, n = read(newsockfd,&clientNumberString,15);
if (n < 0) error("ERROR reading from socket\n");
clientNumber = stoi(clientNumberString);
,只有n
包含您收到的字节数。那么n
如何知道要查看多少字节?另外,假设数字为&#34; 12&#34;但是stoi
只读了&#34; 1&#34;因为&#34; 2&#34;还没发送过。你得错了号码。这似乎表明您从根本上不了解TCP是一个字节流。
答案 1 :(得分:0)
寻找可能出现段错误的内容,请考虑函数CheckNumber。
如果测试有可能超过50,那将是段错误。这是因为在函数结束时没有测试来确保numberClients保持在范围内。
此外,除非您已经写入了超读以进行读写,否则您的通话无法正常工作。考虑&#34;
std :: string s;
读(袜子,&amp; s,10);
这应该在更好的编译器中发出警告,但是不起作用。当以这种方式作为void *传入时,s不会作为字符串类运行。
您可能必须提供一个字符数组:
char s [12];
读(袜子,s,10);
然后,如果要从那里使用字符串类,可以将该缓冲区移动到std :: string。