quote:
Op donderdag 7 augustus 2008 18:24 schreef MrTycho het volgende:Ik heb echt 0 verstand van computers dus kan iemand me ffe een beetje uitgebreid uitleggen wat ik moet dat als ik m'n windows xp cd'tje dr in heb gedaan??
Kleine samenvatting (hoop wel dat je engels kan):
quote:
The socket function creates a new socket and returns a handle to it. The handle is of type SOCKET and is used by all functions that operate on the socket. The only invalid socket handle value is INVALID_SOCKET (defined as ~0), all other values are legal (this includes the value zero!). Its parameters are:
af
The address family to use. Use AF_INET to use the address family of TCP & UDP.
type
The type of socket to create. Use SOCK_STREAM to create a streaming socket (using TCP), or SOCK_DGRAM to create a diagram socket (using UDP). For more information on socket types, see the previous chapter.
protocol
The protocol to be used, this value depends on the address family. You can specify IPPROTO_TCP here to create a TCP socket.
The return value is a handle to the new socket, or INVALID_SOCKET if something went wrong. The socket function can be used like this:
SOCKET hSocket;
hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hSocket==INVALID_SOCKET)
{
// error handling code
}
3. closesocket
int closesocket(SOCKET s);
Closesocket closes a socket. It returns zero if no error occurs, SOCKET_ERROR otherwise. Each socket you created with socket has to be closed with an appropriate closesocket call.
s
Handle to the socket to be closed. Do not use this socket handle after you called this function.
The use of closesocket is pretty straightforward:
closesocket(hSocket);
However, in real situations some more operations are necessary to close the socket properly. This will be discussed later in the tutorial.
4. sockaddr and byte ordering
Because winsock was made to be compatible with several protocols including ones that might be added later (using the SPI) a general way of addressing has to be used. TCP/IP uses an IP and port number to specify an address, but other protocols might do it differently. If winsock forced a certain way of addressing, adding other protocols may not have been possible. The first version of winsock solved this with the sockaddr structure:
struct sockaddr
{
u_short sa_family;
char sa_data[14];
};
In this structure, the first member (sa_family) specifies the address family the address is for. The data stored in the sa_data member can vary among different address families. We will only use the internet address family (TCP/IP) in this tutorial, winsock has defined a structure sockaddr_in that is the TCP/IP version of the sockaddr structure. They are essentially the same structure, but the second is obviously easier to manipulate.
struct sockaddr_in
{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
The last 8 bytes of the structure are not used but are padded (with sin_zero) to give the structure the right size (the same size as sockaddr).
Before proceeding, it is important to know about the network byte order. In case you don't know, byte ordering is the order in which values that span multiple bytes are stored. For example, a 32-bit integer value like 0x12345678 spans four 8-bit bytes. Intel x86 machines use the 'little-endian' order, which means the least significant byte is stored first. So the value 0x12345678 would be stored as the byte sequence 0x78, 0x56, 0x34, 0x12. Most machines that don't use little-endian use big-endian, which is exactly the opposite: the most significant byte is stored first. The same value would then be stored as 0x12, 0x34, 0x56, 0x78. Because protocol data can be transferred between machines with different byte ordering, a standard is needed to prevent the machines from interpreting the data the wrong way.
Network byte ordering
Because protocols like TCP/IP have to work between different type of systems with different type of byte ordering, the standard is that values are stored in big-endian format, also called network byte order. For example, a port number (which is a 16-bit number) like 12345 (0x3039) is stored with its most significant byte first (ie. first 0x30, then 0x39). A 32-bit IP address is stored in the same way, each part of the IP number is stored in one byte, and the first part is stored in the first byte. For example, 216.239.51.100 is stored as the byte sequence '216,239,51,100', in that order.
Apart from the sin_family value of sockaddr and sockaddr_in, which is not part of the protocol but tells winsock which address family to use, all the values in both structures have to be in network byte order. Winsock provides several functions to deal with the conversion between the byte order of the local host and the network byte order:
// Convert a u_short from host to TCP/IP network byte order.
u_short htons(u_short hostshort);
// Convert a u_long from host to TCP/IP network byte order.
u_long htonl(u_long hostlong);
// Convert a u_long from TCP/IP network order to host byte order.
u_short ntohs(u_short netshort);
// Convert a u_long from TCP/IP network order to host byte order.
u_long ntohl(u_long netlong);
You might question why we should need four API functions for such simple operations as swapping the bytes of a short or long (as that's enough to convert from little-endian (intel) to big-endian (network)). This is because these APIs will work even if you are running your program on a machine with other byte ordering than an intel machine (that is, the APIs are platform independent), like Windows CE on a handheld using a big-endian processor. Whether you use these APIs or your own macros/functions is up to you. Just know that the API way is guaranteed to work on all systems.
Back to the sockaddr_in structure, as said above, all members except for sin_family have to be in network byte order. For sin_family use AF_INET. sin_port is the port number of the address (16-bit), sin_addr is the IP address (32-bit), declared as an union to manipulate the full 32-bit word, the two 16-bit parts or each byte separately. sin_zero is not used.
Here are several examples of initializing sockaddr_in structures:
sockaddr_in sockAddr1, sockAddr2;
// Set address family
sockAddr1.sin_family = AF_INET;
/* Convert port number 80 to network byte order and assign it to
the right structure member. */
sockAddr1.sin_port = htons(80);
/* inet_addr converts a string with an IP address in dotted format to
a long value which is the IP in network byte order.
sin_addr.S_un.S_addr specifies the long value in the address union */
sockAddr1.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
// Set address of sockAddr2 by setting the 4 byte parts:
sockAddr2.sin_addr.S_un.S_un_b.s_b1 = 127;
sockAddr2.sin_addr.S_un.S_un_b.s_b2 = 0;
sockAddr2.sin_addr.S_un.S_un_b.s_b3 = 0;
sockAddr2.sin_addr.S_un.S_un_b.s_b4 = 1;
The inet_addr function in the example above can convert an IP address in dotted string format to the appropriate 32-bit value in network byte order. There is also a function called inet_ntoa, which does exactly the opposite.
As a side note, winsock 2 does not require that the structure used to address a socket is the same size of sockaddr, only that the first short is the address family and that the right structure size is passed to the functions using it. This allows new protocols to use larger structures. The sockaddr structure is provided for backwards compatibility. However, since we will only use TCP/IP in this tutorial, the sockaddr_in structure can be used perfectly.