⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 article711.asp.htm

📁 一个网络游戏程序编写的例子
💻 HTM
📖 第 1 页 / 共 5 页
字号:

<BLOCKQUOTE><PRE><FONT FACE="courier new, fixedsys" SIZE="2" COLOR="#000088">
struct hostent {
       char FAR *h_name;
       char FAR *FAR *h_aliases;
       short h_addrtype;
       short h_length;
       char FAR* FAR* h_addr_list;
#define h_addr  h_addr_list[0]
};

</PRE></BLOCKQUOTE>

<P>Nasty structure, really, but fortunately you won't have to worry about much
of it. h_name contains the name of the host. h_aliases is an array of
strings which contain aliases (pseudonyms; nick-names; alternative
identities indicating one and the same thing) of the host. h_addrtype is
simply the type of the addresses in the h_addr_list array. This is
unnecessary for our purposes, because we're already pretty certain what
they are. h_length is the length of the addresses. And finally, where our
interest comes in, the h_addr_list array. This will contain the IP
address(es) of the host that we have looked up. It may come as a surprise,
but there may be more than one IP associated with a host, just as there may
be more than one host associated with an IP.

<P>Usually, we only want the first address in this list of returned addresses
to evade unnecessary complexity. That would be h_addr_list[0]. This, in
past versions, was represented by h_addr; in order to maintain backward
compatibility, a #define has been added to fudge this in Winsock 2.

<BLOCKQUOTE><PRE><FONT FACE="courier new, fixedsys" SIZE="2" COLOR="#000088">
struct hostent *host_addr;
host_addr = gethostbyname("gamedev.net");

</PRE></BLOCKQUOTE>

<P>It is also possible to resolve an IP address into a host name. This can be
done by passing a 32-bit integer representing the IP address in network
byte order to the gethostbyaddr() function. As we have already discussed,
the standard format for the IP address in written form is a decimal-point
denoted set of four base-10 integers. It is for this reason that WinSock
provides the inet_addr() function to convert an IP-address string to an
appropriate unsigned long integer. gethostbyaddr() takes as its first
parameter a pointer to a numeric IP [having been converted from a string
with inet_addr()] in network byte order. Its second parameter is the length of the address,
which is obviously sizeof(unsigned long), and its third parameter is the
type of the address, which is obviously AF_INET in this case. Then the
hostent structure's h_name field will contain the symbolic name of the
host. As a side-note, the inet_ntoa is the converse of the inet_addr
function.

<BLOCKQUOTE><PRE><FONT FACE="courier new, fixedsys" SIZE="2" COLOR="#000088">
struct hostent *host_addr;
host_addr = gethostbyaddr(inet_addr("127.0.0.0"), sizeof(unsigned long), AF_INET);

</PRE></BLOCKQUOTE>

<P><B>Network and Host Byte-order</B>

<P>This is not a very complicated subject. WinSock provides the functions
htons(), ntohs(), htonl() and ntohl() for converting short ints (WORDs) and
long ints (DWORDs) from and to host and network byte order, respectively.
You should perform a ntohl() or ntohs() when appropriate for received data.

<P><B>Sending and Receiving Data</B>

<P>One might expect this to be complicated and arcane. It's not. Let me give
you a hint: The send() function sends data, and the recv() function
receives it. Beyond this, there are a few specifics, but that's the general
model that has been adopted.

<P>First of all, it is important to make the distinction between
connection-oriented and connectionless sockets. The connection-orientation
of a socket is given by one of two things: Whether or not it wears baggy
pants (ask Jim about that one), or what protocol it uses for communication.
The UDP protocol obviously is not oriented at connections, as was already
discussed. The question then arises as to how data is sent from a
connectionless socket if there's no connection (because if there's no
connection, we can't possibly know where to send the data TO).

<P>To send data from a connectionless socket, we use the sendto() function,
which allows us to specify this information. We can also use sendto() for
connection-oriented sockets, but it's really not necessary to do so,
because we already know where our data are supposed to go. Similarly, a
recvfrom() function is provided. This function returns, in addition to
whatever might be waiting for us to receive, relatively detailed
information about the host sending the information to our socket.

<P>So, with no further adieu, let's delve into these functions, which are
really sort of the meat 'n potatoes of the entire WinSock development
experience (...).

<P>send() takes as its first parameter a socket descriptor. Its second
parameter is a pointer to a buffer which will be sent. The third parameter
is the length of the data in the buffer to be sent, in bytes. The fourth
and final parameter is an arcane flag that specifies special conditions for
how the data should be sent. It presently has two possible values,
MSG_DONTROUTE and MSG_OOB. The "don't route" flag is self explanatory: It
specifies that the sent information shouldn't be routed. Don't ask me how
they manage that one. The other value relates to Out-Of-Band data, which is
somewhat interesting but generally outside of our interests. (OOB data is
any sort of data that has a higher priority or a separate meaning than the
normal data transmitted in the datastream. In TCP, this is called urgent
data. Because we're not really concerned with much except getting our data
from one point to another on an internet as game programmers, we're not
going to worry about it. If you'd really like to know about OOB data, for
whatever reason, check out the section about "urgent data" in RFC 793 [the
TCP RFC]).

<BLOCKQUOTE><PRE><FONT FACE="courier new, fixedsys" SIZE="2" COLOR="#000088">
SOCKET s;
char *data = "Hello"
...

//We'd create socket s somewhere in here and connect it

...

send(s, &data, 5, 0);

</PRE></BLOCKQUOTE>

<P>Well, one down. Three to go.

<P>recv() is very similar to send(), with the exception that the buffer
parameter (the second) is now to contain a pointer to a buffer which will
be used to store whatever incoming data there happens to be from a remote
socket. The third parameter is then the length of that buffer. The fourth
parameter is, again, an obscure flag, this time with rather more useful
values. MSG_PEEK can be passed as the flag parameter in recv() to copy the
data from the socket's received buffer into the buffer specified, but to
not remove that data from the socket's received buffer. MSG_OOB is also a
valid flag here, and can be used to take a look at the OOB data coming in
on this socket. It should be noted that recv() can be used on either
connectionless or connection-oriented sockets. The only downside of using
it on connectionless sockets is that you won't know where in Hades (or
should I say Hayes?) the data that you've received is coming from.

<BLOCKQUOTE><PRE><FONT FACE="courier new, fixedsys" SIZE="2" COLOR="#000088">
SOCKET s;
char data[256];
...

//We'd create socket s somewhere in here

...

recv(s, &data, sizeof(data), 0);

</PRE></BLOCKQUOTE>

<P>And then there were two...

<P>The sendto() function is the next most intuitive in our little group, here.
Its first four parameters have the same meaning as they do in the context
of send(). The fifth parameter of sendto() gives the address of the remote
host to send to. This is optional along with the last parameter when the
socket that we're sending from is connected to another socket, but must be
filled for anything meaningful to happen when our socket is connectionless.
Note that this pointer is to a struct of type sockaddr, or in the case of
TCP/IP, sockaddr_in.

<BLOCKQUOTE><PRE><FONT FACE="courier new, fixedsys" SIZE="2" COLOR="#000088">
SOCKET s;
struct sockaddr_in addr;
char data[256];
...

//We'd create socket s somewhere in here and fill in addr

...

sendto(s, &data, sizeof(data), 0, &addr, sizeof(addr));

</PRE></BLOCKQUOTE>

<P>Last but not least, recvfrom(): The hallmark of uselessness. The first four
parameters of recvfrom() are the same as they were for recv(), and the last
two are essentially the same as they were for sendto(), except that they're
now "from" parameters that will hold the address of the remote host. The
exception is that the last parameter of recvfrom(), for some ungodly
reason, is a pointer to the size of the sockaddr_in structure which will
hold the address of the remote host instead of a direct value for it. Don't
ask me what genius thought that one up. Anyway, it should also be noted
that the last two parameters are again optional.

<BLOCKQUOTE><PRE><FONT FACE="courier new, fixedsys" SIZE="2" COLOR="#000088">
SOCKET s;
struct sockaddr_in addr;
char data[256];
int x;
...

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -