Use iostream to encapsulate TCP socket

Source: Internet
Author: User

I. How to UseIostream

TCPThe connection is a stream-oriented connection, which is very consistent with the concept to be expressed by iostream. When using a blocked socket to process data, can I use the powerful string stream processing function provided by iostream to simplify some of our features?ProgramDesign? For example, if you need a certain type of object between the server and the client, you can reload the <operator and istream> operator of ostream and it, in this way, the operators are used to serialize and deserialize objects intuitively and conveniently. In a sense, iostream provides a simple object serialization solution.

As we all know, CIN is a global variable of the istream class, And cout is a global variable of the ostream class. By default, istream and ostream correspond to standard input and output devices. Iostream constructor explicitly requires a streambuf (that isBasic_streambuf <char, char_traits <char>) Class pointer, which means that iostream needs to use streambuf to define specific input/output behaviors.

IostreamIt is a subclass of IOS. There are two methods related to this in IOS: rdbuf (), streambuf pointer returned, rdbuf (streambuf *), and streambuf resetting. Through two functions, we can often implement some very clever behaviors.

Ii. ActuallyIostreamYesStreambufTo read and write data

Let's take a look.StreambufClass. This class is actually more like an interface. Although it is not defined as an abstract class, it can't do anything, which means it is waiting for us to inherit it. At the same time, it also implements some interfaces provided to sub-classes for use.

Streambuf Two buffers are maintained, that isInput bufferAnd output buffer, streambuf is to use these two buffer for data transmission and receiving. Streambuf itself is not responsible for memory application and recovery, so we need to apply for two memory blocks of a certain size during the construction to the streambuf, and then reclaim them during the analysis. /* *
* Streambuf for tcpstream
  */
Class Tcpstreambuf: Public STD: streambuf {
Public :
Tcpstreambuf (Socket socket, Int Buf_size): _ socket (socket), _ bufsize (buf_size ){
Char * Gbuf =   New   Char [_ Bufsize];
Char * Pbuf =   New   Char [_ Bufsize];
Setg (gbuf, gbuf, gbuf );
Setp (pbuf, pbuf + _ Bufsize );
}

Virtual~Tcpstreambuf (){
Delete [] eback ();
Delete [] pbase ();
}

PRIVATE: Int _ bufsize; Socket _ socket;

}

 EachBufferThere are three vertices, that is, the first address, the current pointer, and the tail address.Input bufferThe three verticesEback (),Gptr (),Egptr ()Obtain,Output bufferThe three verticesPbase (),Pptr (),Epptr ().

Setg,SetpThe methods are used to set twoBuffer.

Streambuf The key functions Underflow , Overflow , Sync Three Virtual In Streambuf The three methods in the class have nothing to do, which is exactly the three methods we need to override. When Input buffer The data has been read, Iostream Yes Streambuf Of Underflow When Output buffer When it is filled, Iostream Yes Streambuf Of Overflow To output data. Endl , Ends Or call Flush () Method, Iostream Yes Streambuf Of Sync Method.

UnderflowMethod to extract a certain amount of data from the input streamInput bufferAnd returns the character value of the current position, but does not move the position of the current pointer. If the connection is closed or other errors are returnedEOF. 

/* *
* Called when the input buffer is empty
*/
Virtual Int_type underflow (){
Int RET = Recv (_ socket, eback (), _ bufsize, 0 );
If (Ret >   0 ){
Setg (eback (), eback (), eback () + RET );
Return Traits_type: to_int_type ( * Gptr ());
} Else {
// Ret = 0 | ret = socket_error
Return Traits_type: EOF ();
}
}

 SyncMethod to output all data in the output buffer. 

/* *
* Synchronize the data in the output buffer.
*/
Virtual   Int Sync (){
Int All = Pptr () - Pbase ();
Int Sent =   0 ;
While (Sent < All ){
Int RET = Send (_ socket, pbase () + Sent, all - Sent, 0 );
If (Ret >   0 ){
Sent + = RET;
} Else   If (Ret = Socket_error ){
Return   - 1 ;
}
}
Return   0 ;
}

 OverflowThe output buffer is output first, and then new characters are written to the output buffer. According to msdn, if the new character _ Meta is EOF, traits_type: not_eof (_ Meta) is returned ). 

/* *
* Called when the output buffer overflows
*/
Virtual Int_type overflow (int_type _ Meta = Traits_type: EOF ()){
If (Sync () =   - 1 ){
Return Traits_type: EOF ();
} Else {
If ( ! Traits_type: eq_int_type (_ Meta, traits_type: EOF ())){
Sputc (traits_type: to_char_type (_ Meta ));
}
Return Traits_type: not_eof (_ Meta );
}
}

 Iii. Last step

With this tcp_streambuf, we can use its object pointer to create an iostream.

Tcpstreambuf Sb (socket)
Iostream ( & SB );

 However, C ++ programmers with good Object-oriented thinking may not be satisfied with such writing. It is better to write another raiI class to encapsulate streambuf, while inheriting iostream is a good idea.

Class Tcpstream: Public STD: iostream {
Public :
Tcpstream ( Int Socket, Int Buf_size =   1024 );

Virtual~Tcpstream ();
};

Tcpstream: tcpstream (IntSocket,IntBuf_size/*= 1024*/): STD: iostream (NewTcp_streambuf (socket, buf_size )){
}

Tcpstream ::~Tcpstream (){
Delete rdbuf ();
}

 Okay, let's use it to writeEcho Client. 

# Include " Stdafx. h "
# Include " Tcp_stream.h "

VoidMain (){
Using NamespaceSTD;
Using NamespaceBoost: ASIO: IP;

Boost: ASIO: io_service;
TCP: Socket socket (io_service );

Try {
Socket. Connect (TCP: endpoint (address_v4: loopback (), 1127 ));
Tcpstream TS (socket. Native ());
While ( ! TS. EOF ()){
String Request, response;
CIN > Request;
TS < Request < Endl;
TS > Response;
If ( ! Response. Empty ()){
Cout < Response < Endl;
}
}
} Catch (Boost: System: system_error & Err ){
Cout < Err. What () < Endl;
}

}

 4. Notes

1. iostreamAll exceptions that streambuf may throw are blocked, so do not expect to use the exception mechanism in streambuf. Here I use EOF to indicate errors.

2.The failure of the TCP socket or the other party's connection is unpredictable in advance. This is not like direct detection at the end of the file. Therefore, only EOF () returns true if an error occurs while reading data.

3.If you do not output Endl or ends when outputting data, or call the flush () method, the data will be saved in the output buffer of streambuf. Therefore, pay attention to this when sending data in real time.

4.There is also an article on the InternetArticleThanks for the inspiration from the author of this article, but hisCodeThere is a bug in the bug that often leads to an endless loop after an error, because the EOF value returned by underflow is incorrect, and this bug is corrected here.

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.