gpt4 book ai didi

c++ - 无法让 sigaction 工作

转载 作者:太空宇宙 更新时间:2023-11-04 04:49:16 26 4
gpt4 key购买 nike

我正在尝试创建两个程序:一个基本的套接字服务器和一个客户端,这两个程序都将在 Linux 计算机上运行。服务器的指令是设置一个套接字,接受传入的客户端请求,使用信号设置一个处理程序(用于读取数据缓冲区),然后进入无限 sleep 循环。客户端的指令是设置套接字、连接到服务器并发送数据缓冲区。在担心关闭连接并启动一个新连接之前,我希望按照单个客户端连接的描述来实现此功能(还不确定这些东西应该在哪里循环,我试图保持简单。)我还了解到信号已被弃用,因此我尝试按照此处的示例使用 sigaction:

http://www.linuxprogrammingblog.com/code-examples/sigaction

不幸的是,当我运行代码时发生的情况是这样的:

  1. 服务器启动
  2. 服务器设置套接字
  3. 服务器开始监听并在接受时阻塞(等待客户端)
  4. 客户端启动
  5. 客户端设置套接​​字
  6. 客户端连接到服务器
  7. 服务器解锁
  8. 服务器设置 sigaction
  9. 服务器开始休眠
  10. 客户端调用写入
  11. 客户端似乎写入成功(上帝知道在哪里)
  12. 客户端阻塞等待来自服务器的字节读取确认
  13. 服务器仍在 sleep (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 个小时来解决这个问题,并在来到这里之前尝试了很多方法:

  • 使用 SIGTERM 代替 SIGIO
  • 重新安排操作顺序,以便在接受传入连接之前设置 sigaction
  • 在触发函数内而不是在 sleep 循环内使用 fcntl
  • 使用传递到触发函数的 siginfo_t 结构中的字段描述符
  • 使用 sa_handler 而不是为 sa_siginfo 设置标志(因此不会传递 siginfo_t)
  • 根本不调用 fcntl
  • 切换运行这些程序的服务器
  • 切换这些程序正在使用的端口
  • 在 sleep 循环之前调用所有内容

此时,我的导师告诉我使用已弃用的信号方法,但这似乎是一个糟糕的解决方案。当然 siginfo 现在已经很常见了,使用它不应该这么困难吗?任何有关尝试的建议将不胜感激!

最佳答案

您似乎没有将套接字fcntl'ing为F_SETOWN自己作为控制进程并设置O_ASYNcflags,这会导致套接字实际上向SETOWN'd进程组发送信号。如果您不执行这些操作,则无论您使用 signal(2) 还是 sigaction(2),都不会发送任何信号

关于c++ - 无法让 sigaction 工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12764921/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com