我試圖創建兩個程序:一個基本套接字服務器和一個客戶端,它們都將在Linux機器上運行。服務器的指令是建立一個套接字,接受一個傳入的客戶端請求,使用信號建立一個處理程序(用於讀取數據緩衝區),然後輸入一個無限的睡眠循環。客戶端的指令是建立一個套接字,連接到服務器,併發送一個數據緩衝區。我希望按照單個客戶端連接的描述來工作,然後再擔心關閉連接並啓動一個新連接(不確定這些事情應該循環到哪裏,我試圖保持簡單。)我也瞭解到,信號被棄用,因此,我試圖用的sigaction按照這裏的例子:無法獲取sigaction工作
http://www.linuxprogrammingblog.com/code-examples/sigaction
不幸的是,當我運行我的代碼會發生什麼情況是這樣的:
- 服務器啓動
- 服務器設置插座
- 服務器開始偵聽和蓋帽上接受(等待客戶端)
- 客戶推出
- 客戶端設置了插座
- 客戶端連接到服務器
- 服務器疏導
- 服務器設置的sigaction
- Server開始睡覺
- 客戶端調用寫
- 客戶端似乎成功寫(主知道在哪裏到)
- 等待字節的客戶端塊從服務器讀取確認
- 服務器還在睡覺(的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的設置之前接受傳入的連接
- 使用觸發函數中的fcntl代替睡眠循環
- 內使用場從傳遞到觸發功能
- 的siginfo_t結構使用sa_handler,而不是在所有
- 設置SA_SIGINFO標誌(所以siginfo_t不通過)
- 不調用fcntl切換服務器描述符這些程序上
- 運行的開關,這些程序所使用的睡眠循環
前
您可能想要閱讀'signal(7)'手冊頁。你應該學會更多關於多路複用系統調用,比如'poll(2)'(或者更老的'select(2)')。 –