程式中我们要用 Winsock 1.1,所以我们在程式中有一段为:
WSAStartup((WORD)((1<<8)|1),(LPWSADATA) &WSAData)
其中 ((WORD)((1<<8)|1) 表示我们要用的是 Winsock 「1.1」版本,而WSAData 则是用来储存由系统传回的一些有关此一 Winsock Stack 的资料。
再来我们呼叫 socket() 函式来开启 Server 端的 TCP socket。
socket():建立Socket。
格式: SOCKET PASCAL FAR socket( int af, int type, int protocol );
参数: af 目前只提供 PF_INET(AF_INET)
type Socket 的型态 (SOCK_STREAM、SOCK_DGRAM)
protocol 通讯协定(如果使用者不指定则设为0)
传回值: 成功 - Socket 的识别码
失败 - INVALID_SOCKET(呼叫 WSAGetLastError() 可得知原因)
说明: 此函式用来建立一 Socket,并为此 Socket 建立其所使用的资源。
Socket 的型态可为 Stream Socket 或 Datagram Socket。
我们要建立的是 TCP socket,所以程式中我们的第二个参数为SOCK_STREAM,我们并将开启的这个 socket 号码记在 listen_sd 这个变数。
listen_sd = socket(PF_INET, SOCK_STREAM, 0)
接下来我们要指定一个位址及 port 给 Server 的这个 socket,这样 Client 才知道待会要连接哪一个位址的哪个 port;所以我们呼叫 bind() 函式。
bind():指定 Socket 的 Local 位址 (Address)。
格式: int PASCAL FAR bind( SOCKET s, const struct sockaddr FAR *name,int namelen );
参数: s Socket的识别码
name Socket的位址值
namelen name的长度
传回值: 成功 - 0
失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因)
说明: 此一函式是指定 Local 位址及 Port 给某一未定名之 Socket。使用者若不在意位址或 Port 的值,那麽他可以设定位址为 INADDR_ANY,及 Port 为 0;那麽Windows Sockets 会自动将其设定适当之位址及 Port (1024 到 5000之间的值),使用者可以在此 Socket 真正连接完成後,呼叫 getsockname() 来获知其被设定的值。bind() 函式要指定位址及 port,这个位址必须是执行这个程式所在机器的 IP位址,所以如果读者在设计程式时可以将位址设定为 INADDR_ANY,这样Winsock 系统会自动将机器正确的位址填入。如果您要让程式只能在某台机器上执行的话,那麽就将位址设定为该台机器的 IP 位址。由於此端是 Server 端,所以我们一定要指定一个 port 号码给这个 socket。
读者必须注意一点,TCP socket 一旦选定了一个位址及 port 後,就无法再呼叫另一次 bind 来任意更改它的位址或 port。
在程式中我们将 Server 端的 port 指定为 7016,位址则由系统来设定。
【Server 端建立 socket 并进入监听等待状态】
首先我们先看 Server 端如何建立一个 TCP socket,并使其进入监听等待的状态。
struct sockaddr_in sa;
sa.sin_family = PF_INET;
sa.sin_port = htons(7016); /* port number */
sa.sin_addr.s_addr = INADDR_ANY; /* address */
bind(listen_sd, (struct sockaddr far *)&sa, sizeof(sa))
我们在指定 port 号码时会用到 htons() 这个函式,主要是因为各机器的数值读取方式不同(PC 与 UNIX 系统即不相同),所以我们利用这个函式来将 host order 的排列方式转换成 network order 的排列方式;相同地,我们也可以呼叫ntohs() 这个相对的函式将其还原。(host order 各机器不同,但 network order 都相同)(htons 是针对 short 数值,对於 long 数值则用 hotnl 及 ntohl)指定完位址及 port 之後,我们呼叫 listen() 函式,让这个 socket 进入监听状态。一个 Server 端的 TCP sock