From a qualified C ++ programmer to a network programming expert, it still takes a lot of effort to write a chat program, rather than a high-performance network program that can respond to thousands of users at the same time, it is indeed not easy. The methods described in this article are not directly applied to every specific application, but can only be used as a reference for learning.
Developing High-Performance Online Games is probably the reason why many programmers are motivated to study network programming. Nowadays, large online games require a high number of concurrent online players, and real projects usually adopt multiple servers (groups) the load balancing method first focuses on the situation of a single server.
We all know that the most widely used protocols are UDP and TCP. UDP is an unreliable transmission service and TCP is a reliable transmission service. UDP is like point-to-point data transmission. The sender packages the data with the recipient's address and other necessary information. As for whether the recipient can receive the data, the UDP protocol is not guaranteed. The TCP protocol is like (in fact, they are a hierarchical network protocol). It is built on UDP and incorporates complex mechanisms such as checksum and retransmission to ensure reliable data transmission to the receiver. For details about network protocols, refer to the books about network protocols or refer to RFC. This book directly explores Programming to Implement network programs.
1.1 Introduction to window socket
Windows Socket is inherited from UNIX socket. The latest version is 2.2. For Windows Network Programming, You need to include winsock2.h or mswsock. h In your program. At the same time, you need to add ws2_32. lib or wsock32.lib. After you are ready, you can start to build your first network program.
There are two types of socket programming: blocking and non-blocking. When operating system I/O is implemented, there are several models, including select, wsaasyncselect, wsaeventselect, Io overlapping model, and port completion. To learn basic network programming concepts, you can choose to start from the blocking mode and develop practical programs, non-blocking programming is required (it is hard to imagine that a large server uses the blocking mode for network communication ). When selecting an I/O model, I suggest that beginners start with the wsaasyncselect model because it is simple and practical. However, almost everyone realizes that it is the best choice to complete the port model to develop network programs that respond to thousands of users at the same time.
Since the completion of the port model is the best choice, why don't we write a program that uses the completion of the port, and then you can make some modifications to it. This is indeed a good idea, but when it comes to a project, different situations have different requirements on the program. If you do not have to learn more about network programming, it is impossible to write a program that meets the requirements. Before learning network programming, I suggest that you first learn the network protocol.
1.2 first network program
Because there are many network applications in the server/client mode, and the design of the server is important and difficult. So I want to first discuss the server design method, and then discuss network programs in other modes after completing the server design.
To design a basic network server, follow these steps:
1. initialize Windows Socket
2. Create a listener socket
3. Set the server address and bind the listening port to the address.
4. Start listening
5. Accept Client Connection
6. Communicate with the client
7. terminate the service and clear windows socket and related data, or return to step 1.
We can see that designing the simplest server does not require much code. It can be used as a small chat program or data transmission. But this is just the beginning. Our ultimate goal is to build a network server with large-scale response capabilities. If you have any questions about the use of threads in the operating system, I suggest you review them now, because we often use threads to improve program performance. In fact, threads are used to keep the CPU running, instead of waiting for I/O, or a CPI, the CPU is exhausted. Do not think that the server with more threads has better performance. Thread switching also consumes time. For programs with less I/O wait, the more threads, the lower the performance.
Below are simple server and client source code. (In blocking mode for beginners to understand)
Tcpserver
#include <winsock2.h>
void main(void)
{
WSADATA wsaData;
SOCKET ListeningSocket;
SOCKET NewConnection;
SOCKADDR_IN ServerAddr;
SOCKADDR_IN ClientAddr;
int Port = 5150;
// Initialize Windows Socket 2.2
WSAStartup(MAKEWORD(2,2), &wsaData);
// Create a new socket to respond to client connection requests
ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Enter the server address
// Port 5150
// The IP address is inaddr_any. Use htonl to convert the IP address to the network format.
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(Port);
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// Bind the listening port
bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr));
// Start listening. specify the maximum number of simultaneous connections to 5.
listen(ListeningSocket, 5);
// Accept new connections
NewConnection = accept(ListeningSocket, (SOCKADDR *) &ClientAddr,&ClientAddrLen));
// After a new connection is established, it can communicate with each other. In this simple example, we close the connection directly,
// Close the listening socket and exit the application
//
closesocket(NewConnection);
closesocket(ListeningSocket);
// Release resources related to Windows Socket DLL
WSACleanup();
}
Tcpclient
# include <winsock2.h>
void main(void)
{
WSADATA wsaData;
SOCKET s;
SOCKADDR_IN ServerAddr;
int Port = 5150;
// Initialize Windows Socket 2.2
WSAStartup(MAKEWORD(2,2), &wsaData);
// Create a new socket to connect to the server
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Enter the client address
// Port 5150
// The Server IP address is "136.149.3.29". Use inet_addr to convert the IP address to the network format.
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(Port);
ServerAddr.sin_addr.s_addr = inet_addr("136.149.3.29");
// Send a connection request to the server
connect(s, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr));
// After a new connection is established, it can communicate with each other. In this simple example, we close the connection directly,
// Close the listening socket and exit the application
closesocket(s);
// Release resources related to Windows Socket DLL
WSACleanup();
}
1.3 wsaasyncselect Mode
As mentioned above, there are several network programming modes in windows, which have their own characteristics and vary in complexity and applicability. Is a performance test result for different modes in the book network programming for Microsoft Windows 2nd. The server uses a Pentium 4 1.7 GHz Xeon CPU, 768 m Memory. The client has three PCs configured with Pentium 2 233 MHz, 128 MB memory, Pentium 2 350 MHz, 128 MB memory, itanium 733 MHz, and 1 GB memory.
For detailed analysis of the results, you can refer to the author's description in the original book. I am concerned about which mode is what I need. The first is the server. No doubt, it must be the port mode. The client can also use the complete port, but different modes are supported in different operating systems.
The completion port is not supported in Windows 98, although we can assume that all users have installed Windows 2000 and Windows XP ,. However, for commercial applications, this idea should not be available at this stage. We cannot allow users to upgrade their operating systems to use our clients. Overlapped I/O can be implemented in Windows 98, and the performance is good, but the implementation and understanding will soon catch up with the completion of the port. In addition, the most critical point is that the client program is not used for large-scale network response, and the main task of the client is to perform various operations and other non-network tasks. The author of the original book, including I strongly recommend that you use the wsaasyncselect mode to implement the client, because it is relatively direct and easy to implement, and it can fully meet the client programming needs.
Below is a piece of source code. Although we use it to write the client, I still put its server code, on the one hand, interested friends can use it for testing and learn how to use it to implement the server; on the other hand, the client code can be easily modified from it, for details, refer to the Code in section 1.1.
#define WM_SOCKET WM_USER + 1
#include <winsock2.h>
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
{
WSADATA wsd;
SOCKET Listen;
SOCKADDR_IN InternetAddr;
HWND Window;
// Create the Main Window
Window = CreateWindow();
// Initialize Windows Socket 2.2
WSAStartup(MAKEWORD(2,2), &wsd);
// Create a listener socket
Listen = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Set the server address
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(5150);
// Bind a socket
bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr));
// Set the Windows message so that the window will receive the corresponding message notification when a socket event occurs.
// The server is usually configured with fd_accept │ fd_read | fd_close
// The client usually sets fd_connect │ fd_read | fd_close
WSAAsyncSelect(Listen, Window, WM_SOCKET, FD_ACCEPT │ FD_READ | FD_CLOSE);
// Start listening
listen(Listen, 5);
// Translate and dispatch window messages
// until the application terminates
while (1) {
// ...
}
}
BOOL CALLBACK ServerWinProc(HWND hDlg,UINT wMsg,
WPARAM wParam, LPARAM lParam)
{
SOCKET Accept;
switch(wMsg)
{
case WM_PAINT:
// Process window paint messages
break;
case WM_SOCKET:
// Determine whether an error occurred on the
// socket by using the WSAGETSELECTERROR() macro
if (WSAGETSELECTERROR(lParam))
{
// Display the error and close the socket
closesocket( (SOCKET) wParam);
break;
}
// Determine what event occurred on the
// socket
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
// Accept an incoming connection
Accept = accept(wParam, NULL, NULL);
// Prepare accepted socket for read,
// write, and close notification
WSAAsyncSelect(Accept, hDlg, WM_SOCKET,
FD_READ │ FD_WRITE │ FD_CLOSE);
break;
case FD_READ:
// Receive data from the socket in
// wParam
break;
case FD_WRITE:
// The socket in wParam is ready
// for sending data
break;
case FD_CLOSE:
// The connection is now closed
closesocket( (SOCKET)wParam);
break;
}
break;
}
return TRUE;
}
Section 1.4
So far, I have briefly introduced some windows network programming things and attached some source code. It can be said that readers, especially beginners, may not be able to write programs immediately after reading them, and those codes cannot be directly applied to actual projects. Don't worry. This is the first step in the long journey. Many books are written in the order of basic and application, but I like more direct and practical methods. Besides, the topic I wrote is not commercialized and cannot be invested too much in time. It is just a small help for beginners. I hope that readers can study hard and leave a message to me on my forum if they have any questions. In the future, I will publish some actual code. I hope to make more friends who love programming and Chinese game industry. In the next chapter, I will mainly explain how to complete port programming. This is my original intention to write this article and I hope it will help you.