我有一个TCP客户端/服务器程序集,已经运行了10多年,没有出现问题。 “ head”作业产生大量子进程(我在不支持fork()/ exec()的AS400平台上)。头作业将自己设置为TCP服务器,一旦建立连接,它就会立即通过sendmsg()放弃与其中一个子作业的连接。使用socketpair()等的常用模式。我承认,当12年前我将所有这些都拼凑在一起时,我并不了解正在发生的一切。我发现通过打开的连接的代码如下。因此,头工作正在等待accept()并在accept()返回时调用sendfd()。
int sendfd(int s, int fd)
{
char buf[1];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
int n;
char cms[CMSG_SPACE(sizeof(int))];
buf[0] = 0;
iov.iov_base = buf;
iov.iov_len = 1;
memset(&msg, 0, sizeof msg);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)cms;
msg.msg_controllen = CMSG_LEN(sizeof(int));
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
memmove(CMSG_DATA(cmsg), &fd, sizeof(int));
if ((n = sendmsg(s, &msg, 0)) != iov.iov_len) {
return -1;
}
return 0;
}
因此,子作业运行例程以接收连接。在下面。子进程池有效地运行此例程,例如“ recvfd(0);”。我们的质量保证部门将进行自动化测试,从上周开始,整个子进程将死掉,看似随机,直到第二个子进程都死于EWOULDBLOCK。这个错误让我感到困惑。 recvmsg()始终处于阻塞状态,等待消息。该错误与接收到的套接字有关,还是与接收它使用的“ 0”有关?我的代码中什么都没有改变文件描述符0的质量。我真的为为什么整个子进程死亡而感到困惑。有人告诉我0文件描述符正在更改,但是两个程序的代码中都没有做任何这样的操作。
int recvfd(int s)
{
int ret, fd;
char buf[1];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
char cms[CMSG_SPACE(sizeof(int))];
iov.iov_base = buf;
iov.iov_len = 1;
memset(&msg, 0, sizeof msg);
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)cms;
msg.msg_controllen = sizeof cms;
if ((ret = recvmsg(s, &msg, 0)) < 0) {
return -1;
}
if (ret == 0) {
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
return fd;
}
如果需要更多详细信息,我可以发布更多代码。我必须立即找到此错误,因为它是我们业务的核心。预先感谢!
编辑:这是子代码的摘录。看到'worker_sd'被显式设置为0。我需要解决的问题是退出循环意味着退出程序,但是我不知道是否有处理此错误的方法。
错误消息最终将是: 事务子项以new_sock = -1退出,并且error = Operation将导致进程被挂起。
// worker_sd is explicitly set to 0 because the parent set the child's 0 file descriptor (the usual one
// reserved for standard input) to be the socket over which open descriptors come.
int worker_sd = 0;
jobSwitches.get();
logging_on = jobSwitches[QQJobSwitches::LOGGING_ON] == '1';
debug_on = jobSwitches[QQJobSwitches::DEBUG_ON] == '1';
wait_on_child_process = jobSwitches[QQJobSwitches::WAIT_ON_CHILD] == '1';
if (debug_on) {
CERR << "START: Waiting for a message..." << endl;
}
while ((new_sock = recvfd(worker_sd)) >= 0) {
stringstream sstr;
string ip_str, port_str;
bool success;