2011-06-23 60 views
15

Trên unix tất cả mọi thứ là một tập tin cách tiếp cận chức năng read(), write(), close() không được hỗ trợ trên Win32.Xác định giữa ổ cắm và fd

Tôi muốn bắt chước nó, nhưng không có ý tưởng làm thế nào để phân biệt khi sockổ cắm hoặc fd trên 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) 
{ 
    // ...? 
} 

này nên làm việc như trong:

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" 

Làm thế nào để thực hiện is_net_socket để sử dụng nó như trong:

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 
} 
+0

Bất cứ ai sử dụng _fstat()? – DinGODzilla

Trả lời

3

tôi nghi ngờ ... nhưng tôi không chắc chắn, các fds và ổ cắm trên Windows sử dụng các không gian tên riêng biệt. Do đó số lượng cho một ổ cắm và một tập tin có thể giống nhau, và nó là không thể biết được một trong những bạn đang nói về khi bạn gọi is_net_socket.

Thử in các số ổ cắm và số fd để xem chúng có giống nhau không cùng một lúc.

+0

Trên Windows, WinSock2 (tiêu chuẩn từ NT4) ổ cắm là xử lý đối tượng hạt nhân (đối tượng tập tin, hoặc AFD hoặc xử lý Tcp), đó là lý do tại sao bạn có thể gọi các chức năng ReadFile và WriteFile tiêu chuẩn trên chúng. Tất cả các xử lý đối với các đối tượng hạt nhân đều nằm trong cùng một bảng (cho mỗi tiến trình) và không chồng lên nhau. Ngay cả khi họ đã xảy ra để có các triển khai khác nhau và các giá trị khác nhau, điều đó luôn có thể thay đổi trong phiên bản tiếp theo. Giá trị xử lý sẽ được coi là mờ. –

+0

@ChrisSmith: Chúng tôi đang nói về 'SOCKET' ở đây, đây không phải là 'HANDLE' lần cuối tôi kiểm tra. –

+0

Nếu bạn nhìn vào 'winsock2.h', có dòng' typedef UINT_PTR SOCKET; '. 'UINT_PTR' chứa một trình xử lý hạt nhân thực tế. Đó là lý do tại sao bạn có thể sử dụng nó với các API IO tập tin thông thường: nó sẽ không hoạt động nếu không. 'SOCKET' s đôi khi được gọi là "socket handle" trong tài liệu vì lý do đó. –

3

Nếu thư viện Windows 'C' có dup(), bạn có thể cố gắng đảo ngược nó, điều này sẽ thất bại đối với một ổ cắm nhưng thành công đối với tệp fd. Vì vậy:

int is_net_socket(fd) 
{ 
    return close(dup(fd)) != 0; 
} 

Cảnh báo: lý thuyết chưa được kiểm tra với phụ thuộc chưa được kiểm tra ;-) Lưu ý rằng điều này sẽ trả về kết quả gây hiểu lầm nếu bạn hết fd. Một hiệu ứng phụ khác là nếu nó là một tập tin, nó sẽ bị xóa và mục nhập thư mục của nó được cập nhật. Tất cả trong tất cả nó có thể hút thẳng thắn. Tôi thậm chí có thể downvote nó bản thân mình.

+0

+1: Lạm dụng sáng tạo các nguyên tắc cơ bản của hệ thống i/o! – wallyk

+0

Thật tuyệt vời Tôi thực sự muốn nó có tác dụng phụ miễn phí. Không có ý tưởng nào khác? Điều này là tốt bắt đầu :) – DinGODzilla

+0

Điều này không nên có tác dụng phụ. Chỉ đóng bộ mô tả tệp mở cuối cùng cho một tệp mở, không phải bất kỳ bộ mô tả tệp nào cho nó, nên có các tác dụng phụ. Thực ra tôi nghĩ giải pháp này khá tốt. –

5

Tôi cho rằng bạn có thể sử dụng lựa chọn để truy vấn trạng thái của ổ cắm.

http://msdn.microsoft.com/en-us/library/ms740141%28VS.85%29.aspx

Tôi muốn giới thiệu nhóm desc tập tin và ổ cắm của bạn trong một cấu trúc duy nhất. Bạn có thể khai báo một enum để biết liệu bộ mô tả là một tập tin hay ổ cắm. Tôi biết điều này có thể không năng động như bạn muốn, nhưng nói chung khi bạn tạo các ứng dụng di động, tốt nhất là nên trừu tượng hóa các chi tiết đó.

Ví dụ:

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 
} 
+0

Vâng, theo cách đó, việc biểu diễn các tệp của OS là không quan trọng; bạn đang theo dõi nó cho mình. –

9

Không chắc nơi bạn đang nhận ý kiến ​​cho rằng Windows sẽ không cho phép bạn sử dụng SOCKET xử lý dưới dạng file - như đã nêu rõ ràng trên trang Socket Handles:

Một tay cầm socket có thể tùy chọn là một xử lý tập tin trong Windows Sockets 2. Một tay cầm socket từ một nhà cung cấp Winsock có thể được sử dụng với các hàm không phải Winsock khác như ReadFile, WriteFile, ReadFileEx và WriteFileEx.

Anyways, như để cách để phân biệt giữa chúng trên Windows, xem chức năng NtQueryObject, mà sẽ trả về một tên tay cầm của \Device\Tcp nếu xử lý được truyền cho nó là một mở SOCKET.Đọc phần "Ghi chú" cho cấu trúc được trả về bởi cuộc gọi này.

Lưu ý rằng phương pháp này chỉ có tác dụng XP trở lên, và sẽ thất bại trên Windows 2000 (mà tôi giả sử là đủ tuổi mà nó không ảnh hưởng đến bạn.)