BSD Sockets API 编程
int socket (int family, int type, int protocol);
Creates a socket. Currently
family
can only beAF_INET
(OT does not support IPv6 so there is no AF_INET6 support).protocol
can bePF_INET
orPF_UNSPEC
(both have the same effect of creating an internet socket.type
can beSOCK_STREAM
for TCP sockets orSOCK_DGRAM
for UDP sockets.
socket()
returns a socket file descriptor (sockFD
) which is a small non-negative integer. This file descriptor number should be used for all other socket operations on that socket. Ifsocket()
encounters an error, it will return -1, in which case the application should callGetMITLibError()
to get the error code.NOTE: errno is not supported by the Sockets Library. Use ErrorLib.
int socket_bind (int sockFD, const struct sockaddr *myAddr, int addrLength);
Binds a socket to a local port and/or IP address. Either the port or the IP address in the
struct sockaddr
structure may be wildcarded in which case the library will select appropriate values. To wildcard the port set thesin_port
field of the address to 0. To wildcard the IP, set thesin_addr.s_addr
field of the address toINADDR_ANY
TCP has a port reuse time limit. If an application attempts to bind to the same local port twice in rapid succession, the second attempt will fail with
EADDRINUSE
. Just wait and try again.
socket_bind()
returns 0 on success and -1 on failure. If -1 is returned, callGetMITLibError()
to get the error code.Note that the second argument to
socket_bind()
is actually astruct sockaddr_in*
which is cast to the more generalstruct sockaddr*
because internet addresses are used by the Socket Library.Also, it is not necessary to bind a socket prior to connecting it. If a socket is not bound the library will choose the local port and IP.
int socket_connect (int sockFD, struct sockaddr *servAddr, int addrLength);
Connects a socket to a remote host on a given port. If this is a
SOCK_STREAM
(TCP) socket,socket_connect()
will actually perform TCP negotation to open a connection. If this is aSOCK_DGRAM
(UDP) socket,socket_connect()
will just store the address for use later with other socket operations (this is important to note because ifsockFD
refers to a UDP socket, errors will not be reported prior to an attempt to read or write data on the socket).
socket_connect()
returns 0 on success and -1 on failure. If -1 is returned, callGetMITLibError()
to get the error code.Note that the second argument to
connect
is actually astruct sockaddr_in*
which is cast to the more generalstruct sockaddr*
because internet addresses are used by the Socket Library.
int socket_select (int maxFDsExamined, fd_set *readFDs, fd_set *writeFDs, fd_set*exceptFDs, struct timeval *timeOut);
socket_select()
allows for conditions to be checked on one or more sockets.
maxFDsExamined
should be one greater than value of the largest valued socket descriptor in any of the lists. If you don't wish to calculate this, useFD_SETSIZE
instead. For small numbers of sockets,socket_select()
will be less efficient if FD_SETSIZE is passed.If the bit corresponding to a socket in an
fd_set
is set, that socket will be checked for the condition thefd_set
corresponds to. If the condition they are checked for is true, they will still be set totrue
whensocket_select()
returns (otherwise they will be set to false). Note that the sets are modified bysocket_select()
: thus they must be reset between each call to the function.
fd_set
s can be manipulated using the following macros:
FD_SET(fd, fdset)
Sets socket fd
infdset
to true.FD_CLR(fd, fdset)
Sets socket fd
infdset
to false.FD_ISSET(fd, fdset)
Returns true
iff socketfd
is set to true infdset
.FD_ZERO(fdset)
Sets all the sockets in fdset
to false.Currently only the
readfds
condition (whether there is data to read on a socket) is supported. However, in order to stay compatible with most clients,writefds
(whether there is room in the kernel buffers to write to a socket) behaves as though writing data will succeed (this is usually fine) andexceptfds
behaves as though there are no exception conditions on the socket (exceptfds
will always be returned with all sockets set to false).If
timeout
is NULL,socket_select()
blocks until one of the conditions becomes true for one of the sockets. Iftimeout
is non-NULL,socket_select()
checks for the amount of time corresponding totimeout
and then returns (regardless of whether it has found any conditions to be true). If one of the conditions becomes true for one of the sockets it finds before the timeout has expired, it always returns immediately. To usesocket_select()
in non-blocking mode call it with a non-nulltimeOut
whosetv_sec
andtv_usec
fields are both set to zero.
socket_select()
returns the number of sockets for which the specified conditions are true. If it encounters an error, it will return -1 (in which caseGetMITLibError()
can be called to retrieve the error code.)
int socket_fcntl (int sockFD, int command, int flags);
socket_fcntl()
sets various options on a socket. Currently the only flag supported is O_NONBLOCK which sets a socket to non-blocking mode.If
socket_fcntl()
is called withcommand
equal toF_GETFL
it will return the current flags for the socketsockFD.
The parameterflags
is ignored in this case.If the function is called with
command
equal toF_SETFL
it will replace the socket's flags with those specified byflags.
The correct way to change a flag on a socket is as illustrated in the following example:
flags = socket_fcntl(sockfd, F_GETFL, 0);
flags |= O_NONBLOCK;
err = socket_fcntl(sockfd, F_SETFL, flags);Getting the current flags and modifying them avoids the potential error of clearing other flags.
socket_fcntl()
returns 0 on success and -1 on failure. If -1 is returned, callGetMITLibError()
to get the error code.Note: the corresponding BSD call,
fcntl
takes a variable number of arguments whilesocket_fcntl
does not.
int socket_getpeername (int sockFD, struct sockaddr *peerAddr, int *addrLength);
socket_getpeername()
gets the address of the remote host the socket is connected to, if any. If the socket is not connected,GetMITLibError()
will returnENOTCONN
.
socket_getpeername()
returns 0 on success and -1 on failure. If -1 is returned, callGetMITLibError()
to get the error code.
int socket_getsockname (int sockFD, struct sockaddr *localAddr, int *addrLength);
socket_getsockname()
gets the socket's local address and port.
socket_getsockname()
returns 0 on success and -1 on failure. If -1 is returned, callGetMITLibError()
to get the error code.
int socket_read (int sockFD, void *buffer, UInt32 numBytes);
Reads data from the socket into
buffer
.numBytes
should be the size of the buffer.socket_read()
may not fill the entire buffer.
socket_read()
returns the amount of data which was read. If there is an error, -1 is returned andGetMITLibError()
can be called to retrieve the error code. If 0 is returned, this means that the socket received an EOF (the remote host closed the connection gracefully.) To perform a full read on a socket, continue to callsocket_read()
until the desired number of bytes have been accumulated. Note thatsocket_read()
may block if no data is available to be read. This condition can be checked usingsocket_select()
.The socket must be connected.
Note: the standard library call
read()
is not supported for sockets.
int socket_write (int sockFD, void *buffer, UInt32 numBytes);
Writes data to the socket from
buffer
.numBytes
should be the amount of data in the buffer.socket_write()
may not write out the entire buffer.
socket_write()
returns the amount of data which was written. If there is an error, -1 is returned andGetMITLibError()
can be called to get the error code.The socket must be connected.
int socket_readv (int sockFD, struct iovec *iov, UInt32 iovCount);
The
socket_readv()
function is equivalent tosocket_read()
, but places the input data into theiovcnt
buffers specified by the members of theiov
array:iov0, iov1, ..., iov[iovcnt-1]
. Theiovcnt
argument is valid if greater than 0 and less than or equal toIOV_MAX
.The
iovec
structure contains the following members:
caddr_t iov_base;
int iov_len;
Each
iovec
entry specifies the base address and length of an area in memory where data should be placed. Thesocket_readv()
function always fills an area completely before proceeding to the next.Upon successful completion,
socket_readv()
marks for update thest_atime
field of the file.
socket_readv()
returns the total amount of data which was read into all buffers. If there is an error, -1 is returned andGetMITLibError()
can be called to get the error code. If 0 is returned, this means that the socket got an EOF (the remote host closed the connection gracefully.The socket must be connected.
int socket_writev (int sockFD, struct iovec *iov, UInt32 iovCount);
The
socket_writev()
function performs the same action assocket_write()
, but gathers the output data from theiovcnt
buffers specified by the members of theiov
array:iov[0], iov[1], ..., iov[iovcnt-1]
. Theiovcnt
buffer is valid if greater than 0 and less than or equal toIOV_MAX
.The
iovec
structure contains the following members:
caddr_t iov_base;
int iov_len;
Each
iovec
entry specifies the base address and length of an area in memory from which data should be written.socket_writev()
always writes all data from an area before proceeding to the next.
socket_writev()
returns the amount of data which was written. If there is an error, -1 is returned andGetMITLibError()
can be called to get the error code.The socket must be connected.
int socket_recv (int sockFD, void *buffer, UInt32 numBytes, int flags);
This function is similiar to
socket_read()
with the addition of a final parameter.socket_recv()
reads data from the socket intobuffer
.numBytes
should be the size of the buffer.socket_recv()
may not fill the entire buffer. Ifflags
is set toMSG_DONTWAIT
, thensocket_recv
will not block if not data is available.
socket_recv()
returns the amount of data which was read. If there is an error, -1 is returned andGetMITLibError()
can be called to get the error code. If 0 is returned, this means that the socket received an EOF (the remote host closed the connection gracefully.The socket must be connected.
int socket_send (int sockFD, void *buffer, UInt32 numBytes, int flags);
Similiar to
socket_write()
,socket_send()
writes data to the socket frombuffer
.numBytes
should be the amount of data in the buffer.socket_send()
may not write out the entire buffer. Ifflags
is set toMSG_DONTWAIT
, thensocket_send()
will not block waiting for buffers to become free.
socket_send()
returns the amount of data which was written. If there is an error, -1 is returned andGetMITLibError()
can be called to receive the error code.The socket must be connected.
int socket_recvfrom (int sockFD, void *buffer, UInt32 numBytes, int flags, struct sockaddr *fromAddr, socklen_t *addrLength);
Reads data from the remote host specified by
fromAddr
intobuffer
. The socket must be aSOCK_DGRAM
(UDP) socket.numBytes
should be the size of the buffer.socket_recvfrom()
may not fill the entire buffer. Ifflags
is set toMSG_DONTWAIT
, thensocket_recvfrom()
will not block waiting for data.Note that
fromAddr
will actually be astruct sockaddr_in*
socket_recvfrom()
returns the amount of data which was read. If there is an error, -1 is returned andGetMITLibError()
may be called to get the error code. If 0 is returned, this means that the socket got an EOF (the remote host closed the connection gracefully.
int socket_sendto (int sockFD, void *buffer, UInt32 numBytes, int flags, struct sockaddr *toAddr, socklen_t addrLength);
Writes data the remote host specified by
fromAddr
intobuffer
. The socket must be aSOCK_DGRAM
(UDP) socket.numBytes
should be the amount of data in the buffer.socket_sendto()
may not write out the entire buffer. Ifflags
is set toMSG_DONTWAIT
, thensocket_sendto()
will not block waiting for buffers to become free.Note that
toAddr
will actually be astruct sockaddr_in*
socket_sendto()
returns the amount of data which was written. If there is an error, -1 is returned andGetMITLibError()
can be called to get the error code.
int socket_shutdown (int sockFD, int howTo);
socket_shutdown()
closes one or both directions of a connected socket.howTo
can beSHUT_RD
,SHUT_WR
orSHUT_RDWR
.SHUT_RD
tells it to close the reading side of the connection (reads from the socket will no longer be possible).SHUT_WR
tells it to close the writing half of the socket (this will cause it to send an orderly disconnect to the remote host, telling that host it no longer has anything to write).SHUT_RDWR
tells it to close both halves of the connection (It is still necessary to free the socket withsocket_close()
).
socket_shutdown()
returns 0 on success and -1 on failure. If -1 is returned, callGetMITLibError()
to get the error code.
int socket_close (int sockFD);
socket_close()
frees a socket's resources, disconnecting it from the remote host, if necessary. Both TCP and UDP sockets should be closed with this function.
socket_close()
returns 0 on success and -1 on failure. If -1 is returned, callGetMITLibError()
to get the error code.odsocket.h:
/* * define file about portable socket class. * description:this sock is suit both windows and linux * design:odison * e-mail:odison@126.com> * */ #ifndef _ODSOCKET_H_ #define _ODSOCKET_H_ #ifdef WIN32 #include <winsock.h> typedef int socklen_t; #else #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <arpa/inet.h> typedef int SOCKET; //#pragma region define win32 const variable in linux #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 //#pragma endregion #endif class ODSocket { public: ODSocket(SOCKET sock = INVALID_SOCKET); ~ODSocket(); // Create socket object for snd/recv data bool Create(int af, int type, int protocol = 0); // Connect socket bool Connect(const char* ip, unsigned short port); #region server // Bind socket bool Bind(unsigned short port); // Listen socket bool Listen(int backlog = 5); // Accept socket bool Accept(ODSocket& s, char* fromip = NULL); #endregion // Send socket int Send(const char* buf, int len, int flags = 0); // Recv socket int Recv(char* buf, int len, int flags = 0); // Close socket int Close(); // Get errno int GetError(); //#pragma region just for win32 // Init winsock DLL static int Init(); // Clean winsock DLL static int Clean(); //#pragma endregion // Domain parse static bool DnsParse(const char* domain, char* ip); ODSocket& operator = (SOCKET s); operator SOCKET (); protected: SOCKET m_sock; }; #endifodsocket.cpp
/* * Source file about portable socket class. * * design:odison * e-mail:odison@126.com> * */ #include #include #include "odsocket.h" #ifdef WIN32 #pragma comment(lib, "wsock32") #endif ODSocket::ODSocket(SOCKET sock) { m_sock = sock; } ODSocket::~ODSocket() { } int ODSocket::Init() { #ifdef WIN32 /* http://msdn.microsoft.com/zh-cn/vstudio/ms741563(en-us,VS.85).aspx typedef struct WSAData { WORD wVersion; //winsock version WORD wHighVersion; //The highest version of the Windows Sockets specification that the Ws2_32.dll can support char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYSSTATUS_LEN+1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR * lpVendorInfo; }WSADATA, *LPWSADATA; */ WSADATA wsaData; //#define MAKEWORD(a,b) ((WORD) (((BYTE) (a)) | ((WORD) ((BYTE) (b))) << 8)) WORD version = MAKEWORD(2, 0); int ret = WSAStartup(version, &wsaData);//win sock start up if ( ret ) { cerr << "Initilize winsock error !" << endl; return -1; } #endif return 0; } //this is just for windows int ODSocket::Clean() { #ifdef WIN32 return (WSACleanup()); #endif return 0; } ODSocket& ODSocket::operator = (SOCKET s) { m_sock = s; return (*this); } ODSocket::operator SOCKET () { return m_sock; } //create a socket object win/lin is the same // af: bool ODSocket::Create(int af, int type, int protocol) { m_sock = socket(af, type, protocol); if ( m_sock == INVALID_SOCKET ) { return false; } return true; } bool ODSocket::Connect(const char* ip, unsigned short port) { struct sockaddr_in svraddr; svraddr.sin_family = AF_INET; svraddr.sin_addr.s_addr = inet_addr(ip); svraddr.sin_port = htons(port); int ret = connect(m_sock, (struct sockaddr*)&svraddr, sizeof(svraddr)); if ( ret == SOCKET_ERROR ) { return false; } return true; } bool ODSocket::Bind(unsigned short port) { struct sockaddr_in svraddr; svraddr.sin_family = AF_INET; svraddr.sin_addr.s_addr = INADDR_ANY; svraddr.sin_port = htons(port); int opt = 1; if ( setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0 ) return false; int ret = bind(m_sock, (struct sockaddr*)&svraddr, sizeof(svraddr)); if ( ret == SOCKET_ERROR ) { return false; } return true; } //for server bool ODSocket::Listen(int backlog) { int ret = listen(m_sock, backlog); if ( ret == SOCKET_ERROR ) { return false; } return true; } bool ODSocket::Accept(ODSocket& s, char* fromip) { struct sockaddr_in cliaddr; socklen_t addrlen = sizeof(cliaddr); SOCKET sock = accept(m_sock, (struct sockaddr*)&cliaddr, &addrlen); if ( sock == SOCKET_ERROR ) { return false; } s = sock; if ( fromip != NULL ) sprintf(fromip, "%s", inet_ntoa(cliaddr.sin_addr)); return true; } int ODSocket::Send(const char* buf, int len, int flags) { int bytes; int count = 0; while ( count < len ) { bytes = send(m_sock, buf + count, len - count, flags); if ( bytes == -1 || bytes == 0 ) return -1; count += bytes; } return count; } int ODSocket::Recv(char* buf, int len, int flags) { return (recv(m_sock, buf, len, flags)); } int ODSocket::Close() { #ifdef WIN32 return (closesocket(m_sock)); #else return (close(m_sock)); #endif } int ODSocket::GetError() { #ifdef WIN32 return (WSAGetLastError()); #else return (errno); #endif } bool ODSocket::DnsParse(const char* domain, char* ip) { struct hostent* p; if ( (p = gethostbyname(domain)) == NULL ) return false; sprintf(ip, "%u.%u.%u.%u", (unsigned char)p->h_addr_list[0][0], (unsigned char)p->h_addr_list[0][1], (unsigned char)p->h_addr_list[0][2], (unsigned char)p->h_addr_list[0][3]); return true; }