我正在尝试创建两个程序:基本套接字服务器和客户端,它们都将在Linux机器上运行。服务器的指令是设置套接字,接受传入的客户端请求,使用信号设置处理程序(用于读取数据缓冲区),并进入无限睡眠循环。客户端的说明是设置套接字,连接到服务器,以及发送数据缓冲区。我想让它按照单个客户端连接所描述的那样工作,然后再担心关闭连接并启动一个新的连接(不知道这些东西应该在哪里循环,我试图保持这个简单。)我' ve还了解到信号已被弃用,因此我尝试按照此处的示例使用sigaction:
http://www.linuxprogrammingblog.com/code-examples/sigaction
不幸的是,当我运行代码时会发生什么:
这是我当前的服务器代码:
#include <sys/types.h> // socket, bind
#include <sys/socket.h> // socket, bind, listen, inet_ntoa
#include <netinet/in.h> // htonl, htons, inet_ntoa
#include <arpa/inet.h> // inet_ntoa
#include <netdb.h> // gethostbyname
#include <unistd.h> // read, write, close
#include <string.h> // bzero
#include <netinet/tcp.h> // SO_REUSEADDR
#include <sys/uio.h> // writev
#include <signal.h> // sigaction
#include <sys/time.h> // gettimeofday
#include <unistd.h> // write
#include <fcntl.h> // fcntl
#include <iostream> // cout
using namespace std;
#define BUFSIZE 1500
// Globals
int nreps;
int nbufs;
int newSd;
// Read all the data from the client and output how long it took
void readFromClient(int sig, siginfo_t *siginfo, void *context)
{
cout << "readFromClient triggered!" << endl;
/*
// Set up asynchronous communication
int fd = siginfo->si_fd;
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, FASYNC);
*/
// Declare data buffer
char databuf[BUFSIZE];
// Record start time
struct timeval theTime;
gettimeofday(&theTime, NULL);
int startTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Keep reading until the buffer is full
int nRead = 0;
/*
while((nRead += read(newSd, databuf, BUFSIZE - nRead)) < BUFSIZE)
{
cout << "nRead now: " << nRead << endl;
}
*/
// For testing single byte read
cout << "Reading a byte... " << endl;
char bytebuf[1];
read(newSd, bytebuf, 1);
cout << "SUCCESS" << endl;
// Record finish time
gettimeofday(&theTime, NULL);
int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the receiving time
int receiveTime = finishTime - startTime;
// Display the receiving time
cout << "data-receiving time = " << receiveTime << " usec" << endl;
// Tell the client how much data was read
cout << "Writing amount read... " << endl;
write(newSd, (void*)nRead, 4);
cout << "SUCCESS" << endl;
// Close the socket
cout << "Closing socket... " << endl;
close(newSd);
cout << "SUCCESS" << endl;
// Exit the program
cout << "Exiting!" << endl;
exit(0);
cout << "Why are you still here?" << endl;
}
int main(int argc, char *argv[])
{
cout << "Server is running!" << endl;
// Store command line arguments
int port = atoi(argv[1]);
int nreps = atoi(argv[2]);
int nbufs = atoi(argv[3]);
cout << "port: " << port << endl;
cout << "nreps: " << nreps << endl;
cout << "nbufs: " << nbufs << endl;
// Declare a socket
sockaddr_in acceptSockAddr;
memset((char*)&acceptSockAddr, '\0', sizeof(acceptSockAddr));
acceptSockAddr.sin_family = AF_INET; // Address Family Internet
acceptSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
acceptSockAddr.sin_port = htons(port); // convert host byte-order
// Open a stream-oriented socket
int serverSd = socket(AF_INET, SOCK_STREAM, 0);
// Signal OS to reuse this port once server closes
const int on = 1;
setsockopt(serverSd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int));
// Bind socket to local address
bind(serverSd, (sockaddr*)&acceptSockAddr, sizeof(acceptSockAddr));
// Instruct OS to listen for up to 5 clients
listen(serverSd, 5);
// Declare a new socket
sockaddr_in newSockAddr;
socklen_t newSockAddrSize = sizeof(newSockAddr);
int newSd;
// Set up signal handler for IO from client
struct sigaction action;
memset(&action, '\0', sizeof(action));
action.sa_sigaction = &readFromClient;
action.sa_flags = SA_SIGINFO;
//fcntl(newSd, F_SETSIG, SIGIO); // Fixes problem with si_fd
if(sigaction(SIGIO, &action, NULL) < 0)
{
perror("sigaction");
return 1;
}
// sleep forever
cout << "Sleeping..." << endl;
while(1)
{
cout << "Waiting for client... " << endl;
newSd = accept(serverSd, (sockaddr*)&newSockAddr, &newSockAddrSize);
cout << "SUCCESS" << endl;
cout << "Switching to asynchronous communication... " << endl;
fcntl(newSd, F_SETOWN, getpid());
fcntl(newSd, F_SETFL, FASYNC);
cout << "SUCCESS" << endl;
cout << "Resuming sleep... " << endl;
sleep(10);
}
return 0;
}
这是我目前的客户代码:
#include <sys/types.h> // socket, bind
#include <sys/socket.h> // socket, bind, listen, inet_ntoa
#include <netinet/in.h> // htonl, htons, inet_ntoa
#include <arpa/inet.h> // inet_ntoa
#include <netdb.h> // gethostbyname
#include <unistd.h> // read, write, close
#include <string.h> // bzero
#include <netinet/tcp.h> // SO_REUSEADDR
#include <sys/uio.h> // writev
#include <signal.h> // sigaction
#include <sys/time.h> // gettimeofday
#include <unistd.h> // write
#include <fcntl.h> // fcntl
#include <iostream> // cout
using namespace std;
#define BUFSIZE 1500
#define SIZEOFINT 4
int main(int argc, char *argv[])
{
cout << "Client is running!" << endl;
// Store commmand line arguments
int server_port = atoi(argv[1]);
int nreps = atoi(argv[2]);
int nbufs = atoi(argv[3]);
int bufsize = atoi(argv[4]);
const char* server_name = argv[5];
int testType = atoi(argv[6]);
cout << "server_port: " << server_port << endl;
cout << "nreps: " << nreps << endl;
cout << "nbufs: " << nbufs << endl;
cout << "bufsize: " << bufsize << endl;
cout << "server_name: " << server_name << endl;
cout << "testType: " << testType << endl;
// Check to ensure proper buffer count/sizes
if(nbufs * bufsize != BUFSIZE)
{
cout << "nbufs times bufsize must equal " << BUFSIZE << endl;
exit(0);
}
if(testType < 1 || testType > 3)
{
cout << "test type must be 1, 2, or 3" << endl;
exit(0);
}
// Create buffers
char databuf[nbufs][bufsize];
// Retrieve hostent structure
struct hostent* host = gethostbyname(server_name);
// Declare socket structure
sockaddr_in sendSockAddr;
memset((char*)&sendSockAddr, '\0', sizeof(sendSockAddr));
sendSockAddr.sin_family = AF_INET; // Address Family Internet
sendSockAddr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr*)*host->h_addr_list));
sendSockAddr.sin_port = htons(server_port); // convert host byte-order
// Open stream-oriented socket
int clientSd = socket(AF_INET, SOCK_STREAM, 0);
// Connect socket to server
cout << "Connecting socket to server... " << endl;
int code = connect(clientSd, (sockaddr*)&sendSockAddr, sizeof(sendSockAddr));
cout << "Connection result: " << code << endl;
// Record start time
struct timeval theTime;
gettimeofday(&theTime, NULL);
int startTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Conduct tests
for(int i = 0; i < nreps; i++)
{
switch(testType)
{
case 1:
{
// Multiple write test
cout << "Running multiple write test" << endl;
for(int j = 0; j < nbufs; j++)
{
cout << "Writing buffer " << j << "... " << endl;
write(clientSd, databuf[j], bufsize);
cout << "SUCCESS" << endl;
}
cout << "Finished multiple write test" << endl;
}
case 2:
{
// Vector write test
cout << "Running vector write test" << endl;
struct iovec vector[nbufs];
for(int j = 0; j < nbufs; j++)
{
vector[j].iov_base = databuf[j];
vector[j].iov_len = bufsize;
}
cout << "Writing vector... " << endl;
writev(clientSd, vector, nbufs);
cout << "SUCCESS" << endl;
cout << "Finished vector write test" << endl;
}
case 3:
{
// Single write test
cout << "Running single write test" << endl;
/*
cout << "Writing... ";
write(clientSd, databuf, nbufs * bufsize);
cout << "SUCCESS" << endl;
*/
// For testing single byte write
cout << "writing a byte..." << endl;
char singleByte[1];
write(clientSd, singleByte, 1);
cout << "wrote a byte!" << endl;
cout << "Finished single write test" << endl;
}
}
}
// Record finish time
gettimeofday(&theTime, NULL);
int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the sending time
int sendTime = finishTime - startTime;
// Receive number of bytes read from server
int nReads;
cout << "reading nReads from server... " << endl;
read(clientSd, (void*)nReads, SIZEOFINT);
cout << "SUCCESS" << endl;
// Record read time
gettimeofday(&theTime, NULL);
int readTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the round-trip time
int roundTime = readTime - startTime;
// Display data sending statistics
cout << "Test " << testType << ": data-sending time = " << sendTime;
cout << " usec, round-trip time = " << roundTime << " usec, # reads = ";
cout << nReads << endl;
// Close the socket
cout << "Closing the socket... " << endl;
close(clientSd);
cout << "SUCCESS" << endl;
cout << "Exiting!" << endl;
return 0;
}
我已经花了大约14个小时对此进行故障排除,并在来到这里之前尝试了很多事情:
此时我的导师告诉我使用弃用的信号方法,但这似乎是一个糟糕的解决方案。当然siginfo是现在常见的做法,使用它不应该这么困难吗?对于要尝试的事情的任何建议将不胜感激!
答案 0 :(得分:2)
您似乎没有将自己的套接字fcntl作为控制进程自己f_SETOWN和SETFL O_ASYNC标志,这导致套接字实际向SETOWN'd进程组发送信号。如果你不做那些事情,无论你是使用信号(2)还是信号(2),都不会发送信号
答案 1 :(得分:0)
通过用acceptSockAddr替换对newSockAddr的引用来解决。这是当前的代码,现在以新的和极好的方式出现故障!:
server.cpp:
#include <sys/types.h> // socket, bind
#include <sys/socket.h> // socket, bind, listen, inet_ntoa
#include <netinet/in.h> // htonl, htons, inet_ntoa
#include <arpa/inet.h> // inet_ntoa
#include <netdb.h> // gethostbyname
#include <unistd.h> // read, write, close
#include <string.h> // bzero
#include <netinet/tcp.h> // SO_REUSEADDR
#include <sys/uio.h> // writev
#include <signal.h> // sigaction
#include <sys/time.h> // gettimeofday
#include <unistd.h> // write
#include <fcntl.h> // fcntl
#include <iostream> // cout
using namespace std;
#define BUFSIZE 1500
#define MAX_PENDING 5
#define SIZEOFINT 4
// Globals
int nreps;
int nbufs;
int newSd;
// Read all the data from the client and output how long it took
void readFromClient(int sig, siginfo_t *siginfo, void *context)
{
cout << "readFromClient triggered!" << endl;
// Declare data buffer
char databuf[BUFSIZE];
// Record start time
struct timeval theTime;
gettimeofday(&theTime, NULL);
int startTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Keep reading until the buffer is full
int nRead = 0;
while((nRead += read(newSd, databuf, BUFSIZE - nRead)) < BUFSIZE)
{
cout << "nRead now: " << nRead << endl;
}
// For testing single byte read
/*
cout << "Reading a byte... " << endl;
char bytebuf[1];
read(newSd, bytebuf, 1);
cout << "SUCCESS" << endl;
*/
// Record finish time
gettimeofday(&theTime, NULL);
int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the receiving time
int receiveTime = finishTime - startTime;
// Display the receiving time
cout << "data-receiving time = " << receiveTime << " usec" << endl;
// Tell the client how much data was read
cout << "Writing amount read... " << endl;
write(newSd, (void*)nRead, SIZEOFINT);
cout << "SUCCESS" << endl;
// Close the socket
cout << "Closing socket... " << endl;
close(newSd);
cout << "SUCCESS" << endl;
}
int main(int argc, char *argv[])
{
// Store command line arguments
int port = atoi(argv[1]);
int nreps = atoi(argv[2]);
int nbufs = atoi(argv[3]);
// Declare a socket
struct sockaddr_in acceptSockAddr;
socklen_t len = sizeof(acceptSockAddr);
memset((char*)&acceptSockAddr, '\0', sizeof(acceptSockAddr));
acceptSockAddr.sin_family = AF_INET; // Address Family Internet
acceptSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
acceptSockAddr.sin_port = htons(port); // convert host byte-order
// Open a stream-oriented socket
int serverSd;
if((serverSd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket failure");
exit(1);
}
// Signal OS to reuse this port once server closes
const int on = 1;
setsockopt(serverSd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int));
// Bind socket to local address
if(bind(serverSd, (sockaddr*)&acceptSockAddr, sizeof(acceptSockAddr)) < 0)
{
perror("bind failure");
exit(1);
}
// Instruct OS to listen for up to 5 clients
listen(serverSd, MAX_PENDING);
// Set up signal handler for IO from client
struct sigaction action;
memset(&action, '\0', sizeof(action));
action.sa_sigaction = &readFromClient;
action.sa_flags = SA_SIGINFO;
//fcntl(newSd, F_SETSIG, SIGIO); // Fixes problem with si_fd
if(sigaction(SIGIO, &action, NULL) < 0)
{
perror("sigaction");
exit(1);
}
while(1) // sleep forever
{
cout << "Waiting for client... " << endl;
if((newSd = accept(serverSd, (struct sockaddr*)&acceptSockAddr, &len)) < 0)
{
perror("accept failure");
//exit(1);
}
cout << "SUCCESS" << endl;
fcntl(newSd, F_SETOWN, getpid());
fcntl(newSd, F_SETFL, FASYNC);
}
return 0;
}
client.cpp:
#include <sys/types.h> // socket, bind
#include <sys/socket.h> // socket, bind, listen, inet_ntoa
#include <netinet/in.h> // htonl, htons, inet_ntoa
#include <arpa/inet.h> // inet_ntoa
#include <netdb.h> // gethostbyname
#include <unistd.h> // read, write, close
#include <string.h> // bzero
#include <netinet/tcp.h> // SO_REUSEADDR
#include <sys/uio.h> // writev
#include <signal.h> // sigaction
#include <sys/time.h> // gettimeofday
#include <fcntl.h> // fcntl
#include <iostream> // cout
using namespace std;
#define BUFSIZE 1500
#define SIZEOFINT 4
int main(int argc, char *argv[])
{
// Store commmand line arguments
int server_port = atoi(argv[1]);
int nreps = atoi(argv[2]);
int nbufs = atoi(argv[3]);
int bufsize = atoi(argv[4]);
const char* server_name = argv[5];
int testType = atoi(argv[6]);
// Check to ensure proper buffer count/sizes
if(nbufs * bufsize != BUFSIZE)
{
perror("nbufs times bufsize must equal BUFSIZE");
exit(1);
}
if(testType < 1 || testType > 3)
{
perror("test type must be 1, 2, or 3");
exit(1);
}
// Create buffers
char databuf[nbufs][bufsize];
// Retrieve hostent structure
struct hostent* host = gethostbyname(server_name);
if(!host)
{
perror("unknown hostname");
exit(1);
}
// Declare socket structure
sockaddr_in sendSockAddr;
memset((char*)&sendSockAddr, '\0', sizeof(sendSockAddr));
sendSockAddr.sin_family = AF_INET; // Address Family Internet
sendSockAddr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr*)*host->h_addr_list));
sendSockAddr.sin_port = htons(server_port); // convert host byte-order
// Open stream-oriented socket
int clientSd;
if((clientSd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket failure");
exit(1);
};
// Connect socket to server
if(connect(clientSd, (struct sockaddr*)&sendSockAddr, sizeof(sendSockAddr)) < 0)
{
perror("connect failure");
exit(1);
};
// Record start time
struct timeval theTime;
gettimeofday(&theTime, NULL);
int startTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Conduct tests
for(int i = 0; i < nreps; i++)
{
switch(testType)
{
case 1:
{
// Multiple write test
cout << "Running multiple write test" << endl;
for(int j = 0; j < nbufs; j++)
{
cout << "Writing buffer " << j << "... " << endl;
write(clientSd, databuf[j], bufsize);
cout << "SUCCESS" << endl;
}
cout << "Finished multiple write test" << endl;
}
case 2:
{
// Vector write test
cout << "Running vector write test" << endl;
struct iovec vector[nbufs];
for(int j = 0; j < nbufs; j++)
{
vector[j].iov_base = databuf[j];
vector[j].iov_len = bufsize;
}
cout << "Writing vector... " << endl;
writev(clientSd, vector, nbufs);
cout << "SUCCESS" << endl;
cout << "Finished vector write test" << endl;
}
case 3:
{
// Single write test
cout << "Running single write test" << endl;
cout << "Writing... ";
write(clientSd, databuf, nbufs * bufsize);
cout << "SUCCESS" << endl;
// For testing single byte write
/*
cout << "writing a byte..." << endl;
char singleByte[1];
write(clientSd, singleByte, 1);
cout << "wrote a byte!" << endl;
*/
cout << "Finished single write test" << endl;
}
}
}
// Record finish time
gettimeofday(&theTime, NULL);
int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the sending time
int sendTime = finishTime - startTime;
// Receive number of bytes read from server
int nReads = 0;
cout << "reading nReads from server... " << endl;
read(clientSd, (void*)nReads, SIZEOFINT);
cout << "SUCCESS" << endl;
// Record read time
gettimeofday(&theTime, NULL);
int readTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the round-trip time
int roundTime = readTime - startTime;
// Display data sending statistics
cout << "Test " << testType << ": data-sending time = " << sendTime;
cout << " usec, round-trip time = " << roundTime << " usec, # reads = ";
cout << nReads << endl;
// Close the socket
cout << "Closing the socket... " << endl;
close(clientSd);
cout << "SUCCESS" << endl;
cout << "Exiting!" << endl;
return 0;
}
在关闭第一个客户端连接后尝试与服务器建立第二个客户端连接时仍然存在严重问题。