我在OS X上发现了一个有趣的民意调查。让我在这里说明一下。
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <set>
#include <poll.h>
#define POLL_SIZE 32
int set_nonblock(int fd) {
int flags;
if(-1 == (flags = fcntl(fd, F_GETFL, 0))) {
flags = 0;
}
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
int main() {
int master_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
std::set<int> slave_sockets;
struct sockaddr_in SockAddr;
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(12345);
SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(master_socket, (struct sockaddr *)(&SockAddr), sizeof(SockAddr));
set_nonblock(master_socket);
listen(master_socket, SOMAXCONN);
struct pollfd set[POLL_SIZE];
set[0].fd = master_socket;
set[0].events = POLL_IN;
while(true) {
unsigned int index = 1;
for(auto iter = slave_sockets.begin(); iter != slave_sockets.end(); iter++) {
set[index].fd = *iter;
set[index].events = POLL_IN;
index++;
}
unsigned int set_size = 1 + slave_sockets.size();
poll(set, set_size, -1);
for(unsigned int i = 0; i < set_size; i++) {
if(set[i].revents & POLL_IN) {
if(i) {
static char buffer[1024];
// This line works as expected.
// int recv_size = read(set[i].fd, buffer, 1024);
// This line sends messages in infinite loop?
// I'm checking this with `telnet 127.0.0.1 12345`
int recv_size = recv(set[i].fd, buffer, 1024, SO_NOSIGPIPE);
if ((recv_size == 0) && (errno != EAGAIN)) {
shutdown(set[i].fd, SHUT_RDWR);
close(set[i].fd);
slave_sockets.erase(set[i].fd);
} else if(recv_size > 0) {
send(set[i].fd, buffer, recv_size, SO_NOSIGPIPE);
}
} else {
int slave_socket = accept(master_socket, 0, 0);
set_nonblock(slave_socket);
slave_sockets.insert(slave_socket);
}
}
}
}
return 0;
}
这个程序是用C ++ 11编写的基本echo服务器(但它更像是普通的旧C)。
我在Linux上观察到的行为:应用程序启动,接受客户端套接字(我正在使用telnet 127.0.0.1 12345
),我写"ping"
,按RET并只返回一个“ping”。
Linux规范:
1)clang++ -v
clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
2)uname -a
Linux julian-dell 4.4.0-112-generic #135-Ubuntu SMP Fri Jan 19 11:48:36 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
我在OS X上观察到的行为:应用程序启动,接受客户端套接字,我写“ping”,按RET并返回无限量的"pings"
。在OS X上阻止poll
阻止的唯一方法是使用read
代替recv
来从socket
读取。
OS X规格:
1)clang++ -v
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.3.0
Thread model: posix
2)uname -a
Darwin Julians-MacBook-Pro.local 17.3.0 Darwin Kernel Version 17.3.0: Thu Nov 9 18:09:22 PST 2017; root:xnu-4570.31.3~1/RELEASE_X86_64 x86_64
我的问题是:它是OS X上的错误,预期的行为(也是BSD?)或者我在我的代码中犯了一个错误,这在某种程度上被Linux忽略了?我并不完全理解将recv
更改为read
会如何影响poll
行为 - 它们不是同一个系统调用。
答案 0 :(得分:1)
SO_NOSIGPIPE是socket option
不打算传递给var PouchDB = require('pouchdb');
var fs = require('fs');
var child = require('child_process');
var originalDB = "dbName";
var tempDB = "dbName_clean";
var serviceName = "Apache CouchDB";
var couchDBDataPath = "C:\\bin\\couchdb\\couchdb.2.1.1\\data\\";
var db = new PouchDB('http://URL/' + originalDB);
var db2 = new PouchDB('http://URL/' + tempDB);
console.log("Compacting");
return db.compact().then(function (result) {
console.log("Compacting done, replicating");
var batch_size = 100;
return db2.destroy().then(function () {
db2 = new PouchDB('http://URL/' + tempDB);
return db.replicate.to(db2, {
batch_size: batch_size,
filter: function (doc, req) {
return !doc._deleted;
}
}).on('change', function (info) {
console.log("batch done");
}).on('complete', function () {
console.log('complete');
}).on('paused', function (err) {
// replication paused (e.g. replication up to date, user went offline)
console.log("paused", err);
}).on('active', function () {
// replicate resumed (e.g. new changes replicating, user went back online)
console.log("Active");
}).on('denied', function (err) {
// a document failed to replicate (e.g. due to permissions)
console.log("Denied", err);
}).on('error', function (err) {
// handle error
console.log("error", err);
// reject(err);
}).then(function () {
//replicate done, rename everything
var date = new Date();
console.log("Stopping service");
child.execSync('net stop "' + serviceName + '"');
console.log("Service Stopped");
var newName;
var counter = 0;
do {
newName = "_" + date.getFullYear() + date.getMonth() + date.getDay() + "_" + counter;
counter++;
} while (fs.existsSync(couchDBDataPath + originalDB + newName + ".couch") || fs.existsSync(couchDBDataPath + "." + originalDB + "_design" + newName));
console.log("Renaming original couch to backup labeled", originalDB + newName);
fs.renameSync(couchDBDataPath + originalDB + ".couch", couchDBDataPath + originalDB + newName + ".couch");
fs.renameSync(couchDBDataPath + "." + originalDB + "_design", couchDBDataPath + "." + originalDB + newName + "_design");
console.log("Renaming clean couch back to original", tempDB);
fs.renameSync(couchDBDataPath + tempDB + ".couch", couchDBDataPath + originalDB + ".couch");
fs.mkdirSync(couchDBDataPath + "." + originalDB + "_design");
console.log("Starting service");
child.execSync('net start "' + serviceName + '"');
console.log("Service started");
});
});
}).catch(function (err) {
console.log(err);
});
函数族。
在OS X安装中,SO_NOSIGPIPE设置与MSG_PEEK相同的位,这意味着您的recv()
调用实际上并没有耗尽套接字的数据缓冲区,而只是“窥视”可用数据。因此数据保留在套接字后面,当然然后无限期地轮询可读。
(据推测,您打算设置MSG_NOSIGNAL,但是,正如@melpomene在注释中指出的那样,此行为与在套接字上发送数据有关,而不是接收它。)