C # network programming (basic concepts and operations)-Part.1 [transferred from JimmyZhang blog]

Source: Internet
Author: User
Document directory
  • 1. connection-oriented transmission protocol: TCP
  • 2. Three network chat program modes
  • 1. The server listens on the port
  • 2. Connect the client to the server
  • 3. The server obtains the Client Connection
Introduction

C # The Network Programming series will briefly describe the basic knowledge of network programming. Due to my limited skill in this area, I can only provide some preliminary introductory knowledge, I hope to provide some help to my friends who have just started learning. For more details, see related books.

This is the first article in this series. It describes the basic concepts of Network Programming Based on Socket, including three development modes of TCP protocol, Socket, and chat program, there are two basic operations: listening on the port and connecting to the remote server. The second section describes a simple example: transmitting a string from the client to the server, receiving and printing a string from the server, and changing the string to uppercase, then the string is sent back to the client, and the client prints the returned string. The third is an enhancement in the second article, which describes a problem not solved in the second article, asynchronous transmission is used to complete the same functions as the second one. The fourth shows how to send and receive files between the client and the server; article 5 implements a chat program that can chat online and transfer files. It is actually a comprehensive application of previous knowledge.

Another article related to this article is: C # write a simple chat program, but this chat program is not as powerful as the chat program in this series, and the implementation method is also different.

Basic concepts of network programming 1. connection-oriented transmission protocol: TCP

I don't want to talk too much about the TCP protocol. This is a university course and involves computer science, but I am not an academic school. For this part, I think as a developer, you only need to understand the concepts related to the program, and do not need to study it too hard.

First, we know that TCP isConnection-orientedIt means two remote hosts (or processes, because in fact remote communication is communication between processes, while processes are running programs ), you must perform a handshake to confirm the connection is successful before the actual data can be transmitted. For example, if process A wants to send the string "It's a fine day today" to process B, It must first establish A connection. In this process, it first needs to know the location of process B (host address and port number ). Then we send a request message that does not contain actual data. We can call this message "hello ". If process B receives this "hello", It replies A "hello" to process A, and process a then sends the actual data "It's A fine day today ".

The second thing you need to know about TCP is that it isFull Duplex. It means that if the processes (such as process A and process B) on two hosts establish A connection, data can flow from A to B or B to. In addition, it is stillPoint-to-PointA TCP connection is always between the two. In sending, it is impossible to send data to multiple receivers through a connection. TCP also has a feature calledReliable Data TransmissionAfter the connection is established, the data transmission will surely arrive and be ordered. That is to say, when you send ABC, the receiving party will also receive ABC, instead of BCA or anything else.

One of the most important TCP-related concepts in programming isSocket. We should know the layer-7 network protocol. If we count the above application process, presentation layer, and Session Layer as one layer in general (some textbooks are divided in this way ), the network application program we wrote is located at the application layer, and we all know that TCP is a transport layer protocol, how can we use the transport layer service (message sending or file upload/download) at the application layer )? We all know that in an application, we use interfaces for separation. In the application layer and the transport layer, sockets are used for separation. It is like a small port opened by the transport layer for the application layer. The application sends data remotely or receives data remotely, that is, after the data enters this port, or before the data comes out of this port, we do not know or need to know, and we do not care about how it is transmitted, this belongs to other layers of the network.

For example, if you want to write an email to a friend from afar, we will take the lead in writing a letter, packaging a letter, and writing a letter at the application layer; when we put the mail into the mail box, the port of the mail box is the socket, after entering the socket, It is the transmission layer, network layer, etc. (Post Office, highway traffic management, or route) other levels of work. We never care about how the mail is sent from Xi'an to Beijing. We only know that it is okay to write the mail box. You can use the following two images to represent it:

Note that in the figure above, the two hosts are equivalent, but as agreed,We call one party initiating a request a client and the other end a server.It can be seen that the dialogue between two programs is completed through the socket portal. In fact, the most important information contained in the socket is the two information: local port information (local address and port number) and remote port information (remote address and port number ). Note the subtle changes in the above words. One is the local address and the other is the remote address.

Here is another term.Port. Generally, many applications run on our computers. They may all need to deal with remote hosts, therefore, the remote host requires an ID to identify which application on the local machine it wants to deal with. The ID here is the port. When a port is assigned to an application, the data from this port is always targeted at this application. There is a good example: you can think of the host address as a phone number, and think of the port number as an extension number.

In. NET, although we can directly program the socket. NET provides two classes to encapsulate socket programming, so that we can use it more conveniently. These two classes are TcpClient and TcpListener, and their relationships with sockets are as follows:

The figure above shows that TcpClient and TcpListener encapsulate sockets. It can also be seen that TcpListener is at the position of the receiving stream and TcpClient is at the position of the output stream (in fact, after TcpListener receives a request, it creates a TcpClient, however, it is in the listening state and can be completed by TcpClient. This figure is not accurate enough, but I didn't think of a better method for the moment, and I will be more clear when I see the code later ).

We consider the following situation: two hosts, host A and host B, who did not know where they were at first,When they want to perform a conversation, they always need one party to initiate a connection, while the other party needs to listen on a port of the local machine. When a listener receives a connection request and establishes a connection, it does not need to listen again when it sends and receives data between the listeners. Because the connection is full-duplex, it can use existing connections to send and receive data.We have previously defined that one party that initiates a connection is called the client and the other is called the server. Now we can conclude that:The server is always using the TcpListener class because it needs to establish an initial connection..

2. Three network chat program modes

Implementing an online chat program is supposed to be the content of the last article and the final program of this series. However, I think more encoding will be followed, and there should not be too much content, so I 'd like to put all the content here.

When this mode is used, it is called the full point-to-point mode. At this time, each computer is also a server because it needs to listen on the port. The difficulty in implementing this mode is: how do hosts (or terminals) Know the existence of other hosts? Generally, when a host goes online, it uses UDP for a Broadcast (Broadcast). In this way, it "notifies" other hosts that they are online and describe their locations, when the host receiving the broadcast sends back a response, the host will know the existence of other hosts. I personally don't like this method, but I used this mode in the Article C # compiling a simple chat program. Unfortunately, I didn't implement broadcast, so it is still not perfect.

The second method better solves the above problem. It introduces the server, which is used for broadcasting. The server keeps listening to the port. When a host goes online, it first connects to the server. After receiving the connection, the server places the host (address and port number) send to another online host (marked by a green arrow ). In this way, other hosts will know that the host is online and where it is located for connection and conversation. After the server is broadcast, because each host already knows the location of another host, the dialog between hosts is no longer expressed by the server (indicated by the Black Arrow), but directly connected. Therefore, when using this mode, each host still needs to listen on the port. When a host is offline, it is similar to the logon mode. The server receives a notification and sends it to other hosts.

The third mode is the simplest and most practical one. The login and offline modes of the host are the same as those of the second mode. Note that each host is first connected to the server when it goes online. Then, you can use this path to send messages from host A to host B, host A --> server --> host B. In this way, each host does not need to listen on the port, but only needs to listen on the server, which greatly simplifies development.

For some large files, such as images or files, if you want to send A file from host A to host B, the transmission efficiency through the server will be relatively low, in this case, you can set up A temporary connection between host A and host B to transfer large files. Close the connection after the file transfer ends (marked by an orange arrow ).

In addition, because all messages pass through the server, the server can also cache conversations between hosts, that is, when host A is sent to host B, if host B is offline, the server can cache messages. When host B connects to the server next time, the server automatically sends the cached messages to host B.

This is the final mode used in this series of articles, but it does not implement too many complex functions. Next, our theoretical knowledge has come to an end, starting the next stage-a long coding process.

Basic operation 1. The server listens to the port

Next, we will write some actual code. The first step is to enable listening for a port on the local machine. First, create a console application named "ServerConsole", which represents our server. If you want to communicate with the outside world, the first thing to do is to enable listening to the port, which is like opening a "Door" for the computer ", all requests sent to this "Door" will be received by the system. In C #, follow these steps to create a System by using the local IP address and port number. net. sockets. tcpListener-type instance, and then call the Start () method on the instance to enable listening on the specified port.

Using System. Net; // introduce the two namespaces.
Using System. Net. Sockets;
Using... // omitted

Class Server {
Static void Main (String [] args ){
Console. WriteLine ("Server is running ...");
IPAddress ip = new IPAddress (new byte [] {127, 0, 0, 1 });
TcpListener listener = new TcpListener (ip, 8500 );

Listener. Start (); // Start listening
Console. WriteLine ("Start Listening ...");

Console. WriteLine ("\ n input \" Q \ "key to exit. ");
ConsoleKey key;
Do {
Key = Console. ReadKey (true). Key;
} While (key! = ConsoleKey. Q );
}
}

// Several other common methods for obtaining IPAddress objects:
IPAddress ip = IPAddress. Parse ("127.0.0.1 ");
IPAddress ip = Dns. GetHostEntry ("localhost"). AddressList [0];

In the above Code, we have enabled listening to port 8500. After running the above program, open the "command prompt" and enter "netstat-a" to view the status of all opened ports on the computer. You can find Port 8500 and see that its status is LISTENING. This indicates that it has started LISTENING:

Jimmy TCP: 1030 0.0.0 . 0: 0 LISTENING
Jimmy TCP: 3603 0.0.0 . 0: 0 LISTENING
Jimmy TCP: 8500 0.0.0 . 0: 0 LISTENING
TCP jimmy: netbios-ssn 0.0.0 . 0: 0 LISTENING

After listening on the port is enabled, the server must block it in some way (for example, Console. ReadKey (), so that the program cannot exit because of the end of running. Otherwise, you will not be able to use "netstat-a" to view the port connection status. Because the program has exited, the connection will naturally be interrupted. If you run "netstat-a", the port will not be displayed. Therefore, it is necessary for the program to exit the code by pressing "Q". Each of the following programs will contain this code segment, but I have omitted it to save space.

2. client and server connection 2.1 single client and server connection

After the server starts listening to the port, it can create a client to establish a connection with it. This step is done by creating a TcpClient instance on the client. Each time a new TcpClient is created, a new Socket is created to communicate with the server ,. net will automatically allocate a port number for this Socket. As mentioned above, the TcpClient class is only a package for the Socket. When creating a TcpClient instance, you can specify the address and port number of the remote server in the constructor. In this way, a connection request ("handshake") will be sent to the remote server at the same time of creation. Once the connection is successful, the connection between the two is established. You can also create an object by using the overload non-parameter constructor, and then call the Connect () method to input the remote server address and port number in the Connect () method to establish a connection with the server.

Note that,Whether it is using a constructor with parameters to Connect to the server, or using the Connect () method to establish a connection to the server, it is a synchronous method (or block). It means that the client cannot continue subsequent operations until the client successfully connects to the server, returns a method, or does not store the server, and throws an exception. There is also a method named BeginConnect (), which is used to Implement Asynchronous connections so that the program will not be blocked and you can immediately perform subsequent operations. This may be due to problems such as network congestion, the connection takes a long time to complete. There are a lot of asynchronous operations in network programming, and everything is from simple to difficult. We will discuss about asynchronous operations later. Now we only need to look at synchronous operations.

Create a new console application project named ClientConsole. It is our client, and then add the following code to create a connection with the server:

Class Client {
Static void Main (String [] args ){

Console. WriteLine ("Client Running ...");
TcpClient client = new TcpClient ();
Try {
Client. Connect ("localhost", 8500); // Connect to the server
} Catch (Exception ex ){
Console. WriteLine (ex. Message );
Return;
}
// Print the information of the Connected Server
Console. WriteLine ("Server Connected! {0} --> {1 }",
Client. Client. LocalEndPoint, client. Client. RemoteEndPoint );

// Exit by Q
}
}

In the code above, we call the Connect () method to Connect to the server. Then we printed the connection message: the IP address and port number of the local machine, as well as the remote IP address and port number. The Client attribute of TcpClient returns a Socket object. Its LocalEndPoint and RemoteEndPoint attributes contain local and remote address information respectively. Run the server first and then the code. The output on both sides is as follows:

// Server:
Server is running...
Start Listening...

// Client:
Client Running...
Server Connected! 127.0.0.1: 4761 --> 127.0.0.1: 8500

We can see that the port number used by the client is 4761. As mentioned above, this port number is randomly selected by. NET and does not need to be set. This port number is different each time it is run. Open "command prompt" again and enter "netstat-a". The following output is displayed:

Jimmy TCP: 8500 0.0.0 . 0: 0 LISTENING
TCP jimmy: 8500 localhost: 4761 ESTABLISHED
TCP jimmy: 4761 localhost: 8500 ESTABLISHED

Here we can get a few important information: 1. Port 8500 and port 4761 are connected, and port 4761 is the port used by the client to communicate with the server; 2. Port 8500 remains in the listening status after establishing a connection with the client. This means that a port can communicate with multiple remote ports. Obviously, the default HTTP port used by everyone is 80, but how many browsers does a Web server need to communicate with through this port.

Over 2.2 clients connected to the server

Now that a server port can be connected to multiple clients, let's take a look at how to connect multiple clients to the server. As we mentioned above, a TcpClient is a Socket, so we only need to create multiple TcpClient and then call the Connect () method:

Class Client {
Static void Main (String [] args ){

Console. WriteLine ("Client Running ...");
TcpClient client;

For (int I = 0; I <= 2; I ++ ){
Try {
Client = new TcpClient ();
Client. Connect ("localhost", 8500); // Connect to the server
} Catch (Exception ex ){
Console. WriteLine (ex. Message );
Return;
}

// Print the information of the Connected Server
Console. WriteLine ("Server Connected! {0} --> {1 }",
Client. Client. LocalEndPoint, client. Client. RemoteEndPoint );
}

// Exit by Q
}
}

The most important part of the above Code is the client = new TcpClient () statement. If you put this statement out of the loop, the second loop of recycling will encounter exceptions. The reason is obvious:A TcpClient object corresponds to a Socket, and a Socket corresponds to a port. If you do not use the new operator to recreate an object, this is equivalent to using a port that has been connected to the server to establish a connection with the remote connection again..

If you run "netstat-a" at the "command prompt", the output similar to the following will be displayed:

Jimmy TCP: 8500 0.0.0 . 0: 0 LISTENING
TCP jimmy: 8500 localhost: 10282 ESTABLISHED
TCP jimmy: 8500 localhost: 10283 ESTABLISHED
TCP jimmy: 8500 localhost: 10284 ESTABLISHED
TCP jimmy: 10282 localhost: 8500 ESTABLISHED
TCP jimmy: 10283 localhost: 8500 ESTABLISHED
TCP jimmy: 10284 localhost: 8500 ESTABLISHED

We can see that three connection pairs are created, and port 8500 keeps listening. Here and above we can infer that the Start () method of TcpListener is an Asynchronous Method.

3. The server obtains client connection 3.1 to obtain a single client connection

The above server and client code have established a connection, which can be seen from the port status by using the "netstat-a" command, but this isOperating SystemLet us know. What we need to know now is:How does the server program know that it has established a connection with a client?

After the server starts listening, you can call AcceptTcpClient () on the TcpListener instance to obtain the connection to a client. It returns a TcpClient instance. At this time, it encapsulates the Socket from the server end to the client, while the TcpClient we create on the client end is from the client end to the server end. This method isSynchronization Method(Or block method), which means that when a program calls it, it will wait for a client to connect and then return the result. Otherwise, it will wait. In this case, the subsequent code will not be executed unless a client connection is obtained. A good analogy is the Console. readLine () method, which reads a line of string from the input in the console. If there is input, continue to execute the following code; if there is no input, it will keep waiting.

Class Server {
Static void Main (String [] args ){
Console. WriteLine ("Server is running ...");
IPAddress ip = new IPAddress (new byte [] {127, 0, 0, 1 });
TcpListener listener = new TcpListener (ip, 8500 );

Listener. Start (); // Start listening
Console. WriteLine ("Start Listening ...");

// Gets a connection and interrupts the connection.
TcpClient remoteClient = listener. AcceptTcpClient ();

// Print the information of the connected Client
Console. WriteLine ("Client Connected! {0} <-- {1 }",
RemoteClient. Client. LocalEndPoint, remoteClient. Client. RemoteEndPoint );

// Exit by Q
}
}

When you run this code, you will find that the server stops running listener. AcceptTcpClient () and the following Console. WriteLine () method is not executed. To keep it running, a client must be connected to it. Therefore, we can run the client to connect to it. For simplicity, we only need to enable a port connection on the client:

Class Client {
Static void Main (String [] args ){

Console. WriteLine ("Client Running ...");
TcpClient client = new TcpClient ();
Try {
Client. Connect ("localhost", 8500); // Connect to the server
} Catch (Exception ex ){
Console. WriteLine (ex. Message );
Return;
}
// Print the information of the Connected Server
Console. WriteLine ("Server Connected! {0} --> {1 }",
Client. Client. LocalEndPoint, client. Client. RemoteEndPoint );

// Exit by Q
}
}

In this case, the output of the server and client is:

// Server
Server is running...
Start Listening...
Client Connected! 127.0.0.1: 8500 <-- 127.0.0.1: 5188

// Client
Client Running...
Server Connected! 127.0.0.1: 5188 --> 127.0.0.1: 8500

3.2 obtain connections from multiple clients

Now let's continue to consider what if multiple clients initiate a connection to the server. To avoid scrolling up the browser and viewing the above code, I copied it, let's take a look at the key code of the client:

TcpClient client;

For (int I = 0; I <= 2; I ++ ){
Try {
Client = new TcpClient ();
Client. Connect ("localhost", 8500); // Connect to the server
} Catch (Exception ex ){
Console. WriteLine (ex. Message );
Return;
}

// Print the information of the Connected Server
Console. WriteLine ("Server Connected! {0} --> {1 }",
Client. Client. LocalEndPoint, client. Client. RemoteEndPoint );
}

If the server code remains unchanged, run the server first and then run the client. The following output is displayed:

// Server
Server is running...
Start Listening...
Client Connected! 127.0.0.1: 8500 <-- 127.0.0.1: 5226

// Client
Client Running...
Server Connected! 127.0.0.1: 5226 --> 127.0.0.1: 8500
Server Connected! 127.0.0.1: 5227 --> 127.0.0.1: 8500
Server Connected! 127.0.0.1: 5228 --> 127.0.0.1: 8500

Return to the situation in section 2.2 "Connecting multiple clients to the server" in this chapter:Although three clients connect to the server, the server program only receives one. This is because the server only calls listener. AcceptTcpClient () once, and it only corresponds to one Socket connected to the client.However, the operating system knows that the connection has been established, but it is not processed in our program. Therefore, when we enter "netstat-, the three pairs of connections are successfully established.

To receive connections from three clients, we only need to make a slight modification to the server, and put the AcceptTcpClient method into a do/while loop:

Console. WriteLine ("Start Listening ...");

While (true ){
// Obtain a connection and synchronize it
TcpClient remoteClient = listener. AcceptTcpClient ();
// Print the information of the connected Client
Console. WriteLine ("Client Connected! {0} <-- {1 }",
RemoteClient. Client. LocalEndPoint, remoteClient. Client. RemoteEndPoint );
}

This seems like an endless loop, but it does not quickly exhaust your machine system resources. As we have already said before, AcceptTcpClient () will not continue execution until it receives the connection from the client. It is waiting for most of the time. In addition, the server is almost always running, so this is not necessary, you can also save the "Exit by Q" section of the Code. Run the code again and you will see that the server can receive connections from the three clients.

Server is running...
Start Listening...
Client Connected! 127.0.0.1: 8500 <-- 127.0.0.1: 5305
Client Connected! 127.0.0.1: 8500 <-- 127.0.0.1: 5306
Client Connected! 127.0.0.1: 8500 <-- 127.0.0.1: 5307

This article ends now. Next, let's take a look at how to send and receive data between the server and the client.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.