Windows socket programming sample
A "thread" is a symbolic name for a connection between your computer and a remote computer, and a thread is connected to a socket. In case I've lost you with all that proper terminology, you might think of a thread as an actual, physical, sewing-type thread stretched from one computer to the other, as the common analogy goes.
In order for the threads to be attached to each computer, however, there must be a receiving object that attaches to the threads, and these are called sockets. A socket can be opened on any "port"; which is simply a unique number to distinguish it from other threads, because more than just one connection can be made on the same computer.
A few of these ports have been set aside to serve a specific purpose. Beyond these ports, there are quite a large number of other ports that can be used for anything and everything: over 6,, actually. A few commonly used ports are listed below with their corresponding services:. There are many more ports used for specific purposes that are not shown here.
Typically though, if you wish to use a port that has no specific assigned service, any port from 1, to 6, should be just fine. Of course, if instead you want to listen in on messages sent to and from service ports, you can do that too.
Are you connected to the Internet now? Let's say you are, and you have Internet Explorer or some other web page service running, as well as AOL or some other chat program. On top of that as if the connection wasn't slow enough already , you're trying to send and receive email. What ports do you think are opened, sending and receiving data?
Just like we find out the home address of the people we visit before we get in the car, we have to know the "IP address" of the host we are connecting to, if we are connecting and not just listening a chat program needs to be able to do both.
An IP address is an identification number that is assigned to each computer on the network, and consists of four sets of digits separated by periods. You can view your IP address by running ipconfig.
For the examples shown throughout this tutorial, we will be using what is called the "loop-back address" to test our chat program without being connected to the Internet. This address is Whenever you try to make a connection to this IP, the computer loops the request back to your computer and attempts to locate a server on the specified port.
That way, you can have the server and client running on the same computer. Once you decide to connect to other remote computers, and you've worked the bugs out of your chat program, you will need to get the unique IP address of each to communicate with them over the Internet. Because we as humans are very capable of forgetting things, and because we couldn't possibly hope to remember a bunch of numbers for every web site we visit, some smart individuals came up the wonderful idea of "domain names".
Now, we have neat little names like www. When you type one of these names in your browser window, the IP address for that domain name is looked up via a "router", and once it is obtained or the host is "resolved" , the browser can contact the server residing at that address. For example, let's say I call an operator because I can't remember my girlfriend's phone number fat chance. So, I just tell the operator what her name is and a few other details, but that's not important and she happily gives me the digits.
That's kind of what happens when a request is made for an IP address of any domain name. We have two API that accomplish this task. It's a good idea to make sure and check to see if whoever uses your program types a domain name instead of an IP address, so your program can look up the correct IP address before continuing. Most people, anyway, won't want to remember any IP addresses, so most likely you'll need to translate domain names into IP addresses before you can establish a connection — which requires that the computer must be connected to the Internet.
Then, once you have the address, you're all set to connect. Just when you thought all this thread-socket stuff was going to be simple and easy, we have to start discussing byte order.
This is because Intel computers and network protocols use reversed byte ordering from each other, and we have to covert each port and IP address to network byte order before we send it; else we'll have a big mix up.
Port 25, when not reversed, will not end up being port 25 at all. So, we have to make sure we're speaking the same language as the server when we attempt to communicate with it. Thankfully, we don't have to code all the conversion functions manually; as Microsoft kindly provides us with a few API to do this as well. The four functions that are used to change the byte order of an IP or port number are as follows:.
The "host" computer is the computer that listens for and invites connections to it, and the "network" computer is the visitor that connects to the host. So, for example, before we specify which port we are going to listen on or connect to, we'll have to use the htons function to convert the number to network byte order. An easy way to differentiate between htons and htonl is to think of the port number as the shorter number, and the IP as the longer number which is true — an IP address consists of four sets of up to three digits separated by periods, versus a single port number.
OK, now that we've finally covered the basics, hopefully you are starting to see light at the end of the tunnel and we can move on. Don't worry if you don't understand every aspect of the procedure, for many supplementary facts will be brought to light as we progress. The first step to programming with windows sockets A. There are two versions of Winsock; version one is the older, limited version; and version 2 is the latest edition and is therefore the version we prefer to specify.
You should only need to call these functions once each, the former when you initialize Winsock, and the latter when you are finished. Don't close down Winsock until you are finished, though, as doing so would cancel any connections that your program has initiated or any ports that you are listening on. We understand how sockets work now, hopefully, but up until now we had no idea how to initialize them. The correct parameters must be filled out and passed to a handy API call that begins the socket hopefully.
In this case, we are returned the handle to the socket that we have created. This handle is very "handy" and we must keep it on hand to manipulate the socket's activity. When you are all finished doing your dirty work, it is considered proper programming practice to shut down any sockets that you have opened before your program exits. Of course, when it does, all the ties and connections it has will be forcibly shut down, including any sockets, but it's better to shut them down the graceful way with closesocket.
You will need to pass the socket's handle to this API when you call it. When creating a socket, you will need to pass the "address family", socket "type", and the "protocol type". This parameter specifies how the computer addresses will be interpreted. There is more than just one type of socket; actually, there are many more.
We're close, so close! We've got the "nitty gritty" stuff done and over with, so let's move on the more exiting parts of Winsock programming. Let's try out what we've gone over with a simple program that can connect to a remote computer. Doing this will help you to understand much better how everything works, and helps to prevent information overload!
You'll need to fill out information about the remote host that you are connecting to, and then pass a pointer to this structure to the magic function, connect. This structure and the API are listed below. I highly recommend that you type in all of the examples in this report by hand, instead of copying and pasting it into your compiler.
While I know that doing so will slow you up, I am confident and know from experience that you will learn the process much better that way than if you copy and paste the code. Now that you've had a feel for what it's like to connect to a remote computer, it's time to play the "server" role; so remote computers can connect to you. To do this, we can "listen" on any port and await an incoming connection. As always, we use a few handy API calls:. When you act as the server, you can receive requests for a connection on the port you are listening on: say, for example, a remote computer wants to chat with your computer, it will first ask your server whether or not it wants to establish a connection.
In order for a connection to be made, your server must accept the connection request. Note that the "server" decides whether or not to establish the connection. Finally, both computers are connected and can exchange data. Although the listen function is the easiest way to listen on a port and act as the server, it is not the most desirable.
You will quickly find out when you attempt it that your program will freeze until an incoming connection is made, because listen is a "blocking" function — it can only perform one task at a time, and will not return until a connection is pending. This is definitely a problem, but there are a few solutions for it. First, if you are familiar with multi-threaded applications note that we are not talking about TCP threads here , then you can place the server code on a separate thread that, when started, will not freeze the entire program and the efficiency of the parent program will thus not be impeded.
This is really more of a pain that it needs to be; as you could just replace the listen function with "asynchronous" sockets. If I've caught your attention with that important-sounding name, you can skip ahead to the next section if you like, but I recommend that you stick with me here and learn the fundamentals. We'll spiff up our code later; but for now, let's focus on the bare essentials. At this point, if all has gone according to plan, you're all set to call listen and spy to your heart's content.
The first parameter of listen must be the handle to a socket that you have previously initialized. Of course, whatever port this socket is attached to is the port that you will be listening on. You can then specify, with the next and final parameter, how many remote computers can communicate with your server at the same time. If the socket is up and working fine, all should go well, and when a connection request received, listen will return. This is your clue to call accept , if you wish to establish a connection.
If you compile and run this code, as mentioned before, your program will freeze until a connection request is made. You could cause this connection request by, for example, trying a " telnet " connection. For convenience, a simple client program, iocpclient, was developed to connect and continually send data to the server to stress it using multiple threads.
The server uses the AcceptEx function to multiplex different client connections in a single-threaded Win32 application. This directory contains a basic sample program that demonstrates the use of the WSAPoll function.
The combined client and server program are non-blocking and use the WSAPoll function to determine when it is possible to send or receive without blocking. This sample is more for illustration and is not a high-performance server. This directory contains three basic sample programs that demonstrate the use of multiple threads by a server. The servers demonstrates the use of multiple threads to handle multiple client requests.
This method has scalability issues since a separate thread is created for each client request. This directory contains a basic sample server and client program. So if you explicitly bind first, the source IP address could be incorrect. That is, the source IP might not be the IP address of the interface on which the datagram was actually sent.
Because there is no connection with connectionless protocols, there is no formal shutdown or graceful closing of the connection. When the sender or the receiver is finished sending or receiving data, it simply calls the closesocket function on the socket handle. This releases any associated resources allocated to the socket. In this section, we'll cover a few Winsock API functions that you might find useful when you put together your own network applications.
This function is used to obtain the peer's socket address information on a connected socket. The function is defined as:.
The first parameter is the socket for the connection; the last two parameters are a pointer to a SOCKADDR structure of the underlying protocol type and its length. For datagram sockets, this function returns the address passed to a connect call; however, it will not return the address passed to a sendto or WSASendTo call.
This function is the opposite of getpeername. It returns the address information for the local interface of a given socket. The function is defined as follows:. The parameters are the same as the getpeername parameters except that the address information returned for socket s is the local address information. In the case of TCP, the address is the same as the server socket listening on a specific port and IP interface. Note that this is necessary only between processes; threads in the same process can freely pass the socket descriptors.
This function is defined as:. The first parameter is the socket handle to duplicate. The second parameter, dwProcessId, is the process ID of the process that intends to use the duplicated socket.
Winsock provides no access control, however, so it is up to the programmer to enforce some kind of synchronization. All of the state information associated with a socket is held in common across all the descriptors because the socket descriptors are duplicated, not the actual socket. For example, any socket option set by the setsockopt function on one of the descriptors is subsequently visible using the getsockopt function from any or all descriptors.
If a process calls closesocket on a duplicated socket, it causes the descriptor in that process to become deallocated. The underlying socket, however, will remain open until closesocket is called on the last remaining descriptor.
Issuing either of these calls using any of the shared descriptors cancels any previous event registration for the socket regardless of which descriptor was used to make that registration.
0コメント