Определить между сокетом и fd
В unix все в файле подход к функции read()
, write()
, close()
не поддерживается в Win32.
Я хочу эмулировать его, но понятия не имею, как отличить, когда sock
является сокет или fd на WinSocks2.
//returns 1 if `sock` is network socket,
// 0 if `sock` is file desriptor (including stdio, stderr, stdout), ...
// -1 in none of above
int is_net_socket(int sock)
{
// ...?
}
Это должно работать так:
int mysock = socket(PF_INET, SOCK_STREAM, 0);
int myfd = _open("my_file.txt", _O_RDONLY);
printf("1: %d 2: %d 3: %d 4:%d\n",
is_net_socket(mysock), //1
is_net_socket(myfd), //0
is_net_socket(stdin), //0
is_net_socket(stderr)); //0
// should print "1: 1 2: 0 3: 0 4:0"
Как реализовать is_net_socket
, чтобы использовать его, как в:
int my_close(int sock)
{
#if ON_WINDOWS
switch( is_net_socket(sock) ) {
case 1: return closesocket(sock);
case 0: return _close(sock);
default: //handle error...
}
#else
return close(sock);
#endif
}
Ответы
Ответ 1
Не уверен, когда вы получаете идею о том, что Windows не позволит вам использовать дескрипторы SOCKET
в качестве файлов - как четко указано в Socket Handles страница:
Ручка сокета может быть произвольным файловым дескриптором в Windows Sockets 2. Ручка сокета от поставщика Winsock может использоваться с другими функциями, отличными от Winsock, такими как ReadFile, WriteFile, ReadFileEx и WriteFileEx.
В любом случае, как различать их в Windows, см. функцию NtQueryObject, которая вернет имя дескриптора \Device\Tcp
if дескриптор, переданный ему, является открытым SOCKET
. Прочтите раздел "Примечания" для структуры, возвращаемой этим вызовом.
Обратите внимание, что этот подход работает только с XP и выше, и не будет работать в Windows 2000 (который, как я предполагаю, достаточно велик, что он не влияет на вас.)
Ответ 2
Я полагаю, вы можете использовать select для запроса статуса сокета.
http://msdn.microsoft.com/en-us/library/ms740141%28VS.85%29.aspx
Я бы рекомендовал группировать файлы desc и сокеты в одной структуре. Вы можете объявить перечисление, чтобы указать, является ли дескриптор файлом или сокетом. Я знаю, что это может быть не так динамично, как вы хотите, но обычно при создании переносных приложений лучше всего отвлечь эти детали.
Пример:
enum type { SOCKET, FILE };
typedef struct
{
unsigned int id;
type dataType;
} descriptor_t;
int close(descriptor_t sock)
{
#if WIN32
if (sock.dataType == SOCKET)
return closesocket(sock.id);
else
return _close(sock.id);
#else
return close(sock.id);
#endif
}
Ответ 3
Я подозреваю... но я не уверен, что fds и сокеты в Windows используют отдельные пространства имен. Поэтому число для сокета и файла может быть одинаковым, и невозможно узнать, о котором вы говорите, когда вы вызываете is_net_socket
.
Попробуйте распечатать сокеты и номера fd, чтобы увидеть, совпадают ли они друг с другом одновременно.
Ответ 4
Если в библиотеке Windows 'C' есть dup(), вы можете попытаться свернуть ее, что должно завершиться неудачно для сокета, но преуспеть для файла fd. Итак:
int is_net_socket(fd)
{
return close(dup(fd)) != 0;
}
Предупреждение: непроверенная теория с непроверенной зависимостью;-) Обратите внимание, что это приведет к ошибочным результатам, если у вас закончится fd. Другим побочным эффектом является то, что если это файл, он будет очищен и обновлен его каталог. В общем, это, наверное, отстойно. Я мог бы даже уменьшить его сам.