This article will explain in detail how C # implements network communication between parallel hosts through socket programming. It is a very good blog. Let's take a look at it.
InProgramIn the design, whether it is B/S or C/S mode when it involves data storage and data exchange, there is a concept: database server. This requires that a host with good performance and configuration be used as a server to meet the needs of a large number of clients for frequent access. However, some data exchange requirements are not the same, and the number of communication individuals involved is small. If the "one host and multiple clients" mode is used, this requires a well-configured hardware and the relevant data service software is installed on the software, which will cause a lot of unnecessary costs on the hardware and software, at this time, the network communication advantage of socket between point-to-point parallel objects is brought into play.
In fact, for socket communication, the definitions of servers and clients are not as obvious as those of database servers and clients. It can be said that the servers and clients in socket communication are only opposite, because the objects of network communication are basically at an equal level, the title is defined in this way only to facilitate the description of the two communication hosts.
Because. the establishment of socket communication in. NET is very easy. Therefore, this article mainly introduces the typical application process of a socket: the client sends image requests to the server, and the image server receives the requests, and sends the image code on the server hard disk to the client. After the client obtains the image data, it writes the data into an image file and saves it on the client.
This article mainly introduces an application of socket, so the principle is not discussed here. As for how to establish socket and how to implement the layer-7 protocol of the network, no research or introduction is made here, this article describes how to implement a function that a user wants to send and receive data through the network through communication between two hosts.
I. Communication Flowchart
2. communication-related Code
This document uses the Windows console program as an example to introduce the function.
Whether it is a communication server or a communication client, this article uses a continuously running thread to listen on the port, and makes the communication-related variable functions into a class in program. CS only initializes some parameters and then establishes the communication thread. The Code is as follows:
2.1 Server
Program. CS:
Using system; using system. net; using system. net. sockets; using system. threading; namespace consolesocketsdemo {class program {static void main (string [] ARGs) {int sendpicport = 600; // port int recv1_port = 400 for sending images; // After the port receiving the request is enabled, the system listens socketserver socketserverprocess = new socketserver (recv1_port, sendpicport); thread tsocketserver = new thread (New threadstart (socketserverprocess. thread); // call when the thread starts The method used is threadproc. thread tsocketserver. isbackground = true; // If isbackground is set to true, the background thread will automatically destroy tsocketserver Based on the destruction of the main thread. start (); console. readkey (); // directly add a console in main. read () is not good. You must press the button to exit. }}}
Socketserver. CS:
Using system; using system. text; using system. net; using system. net. sockets; using system. io; namespace consolesocketsdemo {class socketserver {socket srecvcmd; int recv1_port; // receive image Request command int sendpicport; // send image command public socketserver (INT recvport, int sendport) {recv1_port = recvport; sendpicport = sendport; // create a local socket and listen on port 4000 all the time. ipendpoint recv1_localendpoint = new ipendpoint (IPaddress. any, Recv Cmdport); srecvcmd = new socket (addressfamily. interNetwork, sockettype. stream, protocoltype. TCP); srecvcmd. BIND (recv1_localendpoint); srecvcmd. listen (100);} public void thread () {While (true) {system. threading. thread. sleep (1); // Add a "Short Time" sleep to the dead loop inside each thread, so that the resources occupied by the thread can be promptly released. Try {socket srecv1_temp = srecvcmd. accept (); // accept extracts the first pending connection request from the connection request queue of the listening socket synchronously, and then creates and returns the new socket srecv1_temp. setsocketopt Ion (socketoptionlevel. socket, socketoptionname. receivetimeout, 5000); // sets the receiving data timeout srecv1_temp. setsocketoption (socketoptionlevel. socket, socketoptionname. sendtimeout, 5000); // sets the sending data timeout srecv1_temp. setsocketoption (socketoptionlevel. socket, socketoptionname. sendbuffer, 1024); // sets the sending buffer size of 1 K srecv1_temp. setsocketoption (socketoptionlevel. socket, socketoptionname. receivebuffer, 1024); // set the size of the receiving buffer to 1 K byte [] Recvbytes = new byte [1024]; // enable a buffer to store the received information srecv1_temp. receive (recvbytes); // put the read content in recvbytes string strrecvcmd = encoding. default. getstring (recvbytes); // The program runs to this place, you have received the remote command. // **************** // decodes the command, and execute the corresponding operation ---- send the local image as follows // ************* string [] strarray = strrecvcmd. split (';'); If (strarray [0] = "picrequest") {string [] strremoteendpoint = srecv1_temp. remoteendpoint. tostring (). s Plit (':'); // The request IP address and port of the remote terminal, such as 127.0.0.1: 4000 string strremoteip = strremoteendpoint [0]; sentpictures (strremoteip, sendpicport ); // send the local image file recvbytes = NULL;} catch (exception ex) {console. write (ex. message );}}} /// <summary> /// send an image to the remote client /// </Summary> /// <Param name = "strremoteip"> remote client IP address </param>/ // <Param name = "sendport"> send Image Port </param> Private Static void sentpictures (string strremoteip, Int sendport) {string Path = "d :\\ images \"; string strimagetag = "image "; // The image name contains all image files. Try {string [] picfiles = directory. getfiles (path, strimagetag + "*", searchoption. topdirectoryonly); // The number of files that meet the requirements if (picfiles. length = 0) {return; // no image, no processing} Long sendbytestotalcounts = 0; // total length of the sent data stream // message header: command ID + number of files + ...... File I Length + String strmsghead = "picresponse;" + picfiles. length + ";"; // Message Body: byte [] [] msgpicbytes = new byte [picfiles. length] []; for (Int J = 0; j <picfiles. length; j ++) {filestream FS = new filestream (picfiles [J]. tostring (), filemode. open, fileaccess. read); binaryreader reader = new binaryreader (FS); msgpicbytes [J] = new byte [FS. length]; strmsghead + = FS. length. tostring () + ";"; sendbytestotal Counts + = FS. length; reader. read (msgpicbytes [J], 0, msgpicbytes [J]. length);} byte [] msgheadbytes = encoding. default. getbytes (strmsghead); // convert the message header string to the byte array sendbytestotalcounts + = msgheadbytes. length; // data stream to be sent: Data header + Data body byte [] sendmsgbytes = new byte [sendbytestotalcounts]; // total number of groups to be sent for (INT I = 0; I <msgheadbytes. length; I ++) {sendmsgbytes [I] = msgheadbytes [I]; // data header} int Index = msgheadbytes. le Ngth; For (INT I = 0; I <picfiles. length; I ++) {for (Int J = 0; j <msgpicbytes [I]. length; j ++) {sendmsgbytes [index + J] = msgpicbytes [I] [J];} index + = msgpicbytes [I]. length;} // The program is executed here. The packets with image information are prepared // picresponse; 2; 94223; 69228; // + Picture 1 bit stream + ...... Figure 2 bit stream try {# region send image socket ssendpic = new socket (addressfamily. interNetwork, sockettype. stream, protocoltype. TCP); IPaddress = IPaddress. parse (strremoteip); // remoteip = "127.0.0.1" try {ssendpic. connect (IPaddress, sendport); // connect to the ssendpic of the unprovoked client host. send (sendmsgbytes, sendmsgbytes. length, 0); // send a local image} catch (system. exception e) {system. console. the write ("sentpictures function encountered an exception when establishing a remote connection:" + E. message);} finally {ssendpic. close () ;}# endregion} catch {}} catch (exception ex) {console. write (ex. message );}}}}
2.2 Client
Program. CS:
Using system; using system. text; using system. net; using system. net. sockets; using system. threading; namespace consoleclientsocketdemo {class program {static void main (string [] ARGs) {int recvport = 600; // The client listens to port 600 all the time. The port that receives the image is recvpic = new recvpic (recvport ); // The listener receives images from the image server and the client command thread trecvpic = new thread (New threadstart (recvpic. thread); trecvpic. isbackground = true; trecvpic. start (); String strpicserverip = "127.0.0.1"; // IP----127.0.0.1 of the image server (localhost) -- Take the local machine as an example int sendrequestport = 400; // send the image request port sendstrmsg (strpicserverip, sendrequestport); console. readkey (); // directly add a console in main. read () is not good. You must press the button to exit.} /// <Summary> /// send a string request image to the target host /// </Summary> /// <Param name = "strpicserverip"> Target Image Server IP address </param> // <Param name = "sendrequestport"> port on which the target image server receives the request </param> Private Static void sendstrmsg (string strpicserverip, int sendrequestport) {// You can encode the string. Article Which can transmit various information. Currently, there are three encoding methods: // 1. custom connection string encoding-trace // 2. JSON encoding-lightweight // 3. XML encoding -- weight string strpicrequest = "picrequest; Hello world, need some pictures ~! "; // Image request ipendpoint = new ipendpoint (IPaddress. parse (strpicserverip. tostring (), sendrequestport); socket answersocket = new socket (addressfamily. interNetwork, sockettype. stream, protocoltype. TCP); try {answersocket. connect (ipendpoint); // establish a socket connection byte [] sendcontents = encoding. utf8.getbytes (strpicrequest); answersocket. send (sendcontents, sendcontents. length, 0); // sends binary data} catch (exception ex) {console. write (ex. message);} finally {answersocket. close () ;}}} recvpic. CS:
Using system; using system. text; using system. net; using system. net. sockets; using system. io; namespace consoleclientsocketdemo {class recvpic {socket srecvpic; // socket int recvpicport for receiving images; // public recvpic (INT recvport) {recvpicport = recvport; ipendpoint localendpoint = new ipendpoint (IPaddress. any, recvpicport); srecvpic = new socket (addressfamily. interNetwork, sockettype. stream, protocoltyp E. TCP); srecvpic. BIND (localendpoint); srecvpic. listen (100);} public void thread () {While (true) {system. threading. thread. sleep (1); // Add a "Short Time" sleep to the dead loop inside each thread, so that the resources occupied by the thread can be promptly released. Try {socket srecvpictemp = srecvpic. accept (); // keep waiting for the socket request, and create a socket that is the same as the request, overwrite the original socket srecvpictemp. setsocketoption (socketoptionlevel. socket, socketoptionname. receivetimeout, 5000); // sets the receiving data timeout srecvpictemp. setsocketoptio N (socketoptionlevel. socket, socketoptionname. sendtimeout, 5000); // sets the time-out for sending data to srecvpictemp. setsocketoption (socketoptionlevel. socket, socketoptionname. sendbuffer, 1024); // sets the size of the sending buffer-1 K size srecvpictemp. setsocketoption (socketoptionlevel. socket, socketoptionname. receivebuffer, 1024); // set the size of the receiving buffer # region first retrieves the data header information and parses the header byte [] recvheadbytes = new byte [1024]; // obtain 1 k of data first and extract the data header srecvpictemp. receive (recvhea Dbytes, recvheadbytes. length, 0); string recvstr = encoding. utf8.getstring (recvheadbytes); string [] strheadarray = recvstr. split (';'); // picresponse; 2; 94223; 69228; string strheadcmd = strheadarray [0]; // the header command int piccounts = convert. toint32 (strheadarray [1]); // number of images contained in the data stream int [] piclength = new int [piccounts]; // The length of each image for (INT I = 0; I <piccounts; I ++) {piclength [I] = convert. toint32 (strheadarray [I + 2 ]) ;}# Endregion int offset = 0; // The length of the Data header for (int K = 0; k <strheadarray. length-1; k ++) {Offset + = strheadarray [K]. length + 1; // because of the semicolon} int picoffset = recvheadbytes. length-offset; // when extracting the data header, the first image has been extracted with a part of IF (strheadcmd = "picresponse") {# region stores the image-to save memory, you can save the image for (INT I = 0; I <piccounts; I ++) {byte [] recvpicbytes = new byte [(piclength [I])] Every time you receive the image. // receive only one image at a time if (I = 0) // the first image has Some of the data headers have been extracted. {Byte [] recvfirstpicbuffer = new byte [piclength [I]-picoffset]; srecvpictemp. receive (recvfirstpicbuffer, recvfirstpicbuffer. length, 0); For (Int J = 0; j <picoffset; j ++) {recvpicbytes [J] = recvheadbytes [Offset + J]; // The first part of the first image} For (Int J = 0; j <recvfirstpicbuffer. length; j ++) // the second half of the first image {recvpicbytes [picoffset + J] = recvfirstpicbuffer [J];} // write the image to the file savepicture (recvpicbytes, "-0 ");} Else {srecvpictemp. receive (recvpicbytes, recvpicbytes. length, 0); // obtain the length of an image savepicture (recvpicbytes, "-" + I. tostring (); // write image data to a file }}# endregion }} catch (exception ex) {console. write (ex. message );} finally {}}/// <summary> // Save the image to the specified path // </Summary> /// <Param name = "picbytes"> bitstream </param> // <Param name = "picnum"> image no. </param> Public void savepicture (byte [] picbytes, string picnum) {String filename = "receivepic"; if (! Directory. exists ("E: \ images \") directory. createdirectory ("E: \ images \"); If (file. exists ("E: \ images \" + filename + picnum + ". jpg ") return; filestream FS = new filestream (" E: \ images \ "+ filename + picnum + ". jpg ", filemode. openorcreate, fileaccess. write); FS. write (picbytes, 0, picbytes. length); FS. dispose (); FS. close ();}}}
Iii. Test the socket connection method. Telnet for remote logon.
You can write the socket program on the client and server at the same time, and then conduct joint debugging. You can also write only one socket program at a time, and then test the socket connection using the following method.
Generally, you can use remote logon to test whether the connection is successful. For example, you can test whether the connection is successful on port 400 of the local machine:
"Run-> cmd-> Telnet 127.0.0.1 400"
If you do not run a program that continuously listens to port 400 of the local machine, a connection failure prompt will appear:
If the connection is successful, another window will pop up:
If a breakpoint is set in the listener thread, after the connection is successful
Socket srecv1_temp = srecvcmd. Accept ();
And then the statement.
Attachment: socketdemo.rar
Description of nearby demo programs:
1. Create with vs2005.
2. The main function is to send an image request to Alibaba Cloud. Alibaba Cloud sends the image 0.jpg and image1.jpg files under the D-disk imagedirectory to host B. Then, host B decodes and writes the image files to the image directory of the e-disk.
3. to facilitate debugging, the demo program places both the server and client on the local machine, that is, localhost or 127.0.0.1, that is, the final effect of this program is to transfer two images with the specified name under the D disk image directory of the local machine to the E disk image directory. Therefore, before running this program, set two image files named image0.jpg and image1.jpg in the d:/imagedirectory.
4. Run the server program before running the client program.