【发布时间】:2013-10-17 00:08:33
【问题描述】:
我正在尝试实现一对能够通过 Unix 套接字交换信息的服务器/客户端程序。问题是客户端不断被服务器重置并循环重新运行,并且在第一次之后我无法向套接字发送/接收数据。现在我有这样的东西:
服务器:
int main(int argc, char const *argv[]){
unix_socket server;
server.initSocket(DEFAULT_SOCKET_PATH,SERVER_MODE);
server.wait();
bool first=true;
for (int i = 0; i < 30; ++i)
{
//send & receive data
server.closeSocket();
first=false;
}
return 0;
}
客户:
int loop_controller(){
unix_socket client;
client.initSocket(DEFAULT_SOCKET_PATH,CLIENT_MODE);
// receive & send data
client.closeSocket();
}
int main () {
for (int i = 0; i < 30; ++i){
loop_controller();
}
return 0;
}
unix_socket 类的 initSocket()、wait() 和 closeSocket() 成员(服务器模式 0,模式 1对于客户):
void unix_socket::initSocket(const char* sock_path, const int sc_mode){
if (sc_mode==0){
if (mode != sc_mode) mode=sc_mode;
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
//exit(1);
}
// ---
local.sun_family = AF_UNIX;
strcpy(local.sun_path, sock_path);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(sock, (struct sockaddr *)&local, len) == -1) {
close(sock);
perror("bind");
//exit(1);
}
// ---
} else if(sc_mode==1) {
if (mode != sc_mode) mode=sc_mode;
if ((client_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
//exit(1);
}
// ---
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, sock_path);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(client_sock, (struct sockaddr *)&remote, len) == -1) {
perror("connect");
//exit(1);
}
// ---
} else printf("Invalid sc_mode argument: %d\n",sc_mode);
}
//...
void unix_socket::wait(){
if (mode==0){
if (listen(sock, 5) == -1) {
perror("listen");
//exit(1);
}
t = sizeof(remote);
if ((client_sock = accept(sock, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
//exit(1);
}
} else printf("Invalid call to wait(): mode %d\n, must be 0",mode);
}
//...
void unix_socket::closeSocket(){
//close(sock);
close(client_sock);
}
//...
但是,当使用 Valgrind 运行这两个程序时,我收到了 SIGPIPE 错误:
==5384==
==5384== Process terminating with default action of signal 13 (SIGPIPE)
==5384== at 0x573DDA2: send (send.c:28)
==5384== by 0x405910: unix_socket::sendMsg(char, double) (in .../server)
==5384== by 0x405B6C: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in .../server)
==5384== by 0x402044: main (in .../server)
==5384==
我猜在关闭/重新打开套接字时某些事情没有正确完成。什么是正确的程序?
【问题讨论】:
-
在服务器端,您所说的重新打开是在哪里?我所看到的只是循环的第一遍结束。
-
如果您尝试写入已经关闭(并且阻塞?)的套接字,您将获得
SIGPIPE。大多数应用程序可以很好地使用signal(SIGPIPE, SIG_IGN)[尽管不要从您的库中这样做] 来忽略此类信号 -
此外,您的
perror()调用应在操作失败后立即进行。当您执行close(sock)时,errno由close()设置以指示其成功或失败,因此您将获得由close()设置的errno而不是bind()