Socket programming BASICS (I)

Source: Internet
Author: User
Tags sendmsg set socket socket error

In Windows, interfaces can communicate in two ways: Blocking Mode and non-blocking mode. When performing I/O operations on a set of interfaces working in blocking mode, the function must wait until relevant operations are completed.

(Or you can use wsacancelblockingcall (callback) to call a blocking operation ).

This blog is designed to implement blocking I/O socket programming in windows.

Simple TCP blocking mode: client code:
Const char host_address [] = "127.0.0.1"; const int host_port = 8888; const int default_buffer = 1 <12; // 4 kvoid testclient () {wsadata; // typedef unsigned short word; 16-bit unsigned integer Word version = makeword (2, 2); // 0x0202int err = wsastartup (version, & wsadata ); // cout <(INT) hibyte (Version) <(lobyte (Version) = 2); If (0! = ERR) {cerr <"socket2.2 initialization failed !, Exit "; exit (0);} socket sockclient = socket (af_inet, sock_stream, 0); If (invalid_socket = sockclient) {cerr <" socket creation failed! Exit "; wsacleanup (); exit (0) ;}// set the Sending address sockaddr_in addrto; memset (& addrto, 0, sizeof (addrto); addrto. sin_family = af_inet; // TCP/IP protocol addrto. sin_addr.s_addr = inet_addr (host_address); addrto. sin_port = htons (host_port); If (connect (sockclient, (sockaddr *) & addrto, sizeof (addrto) = socket_error) {cerr <"failed to connect. \ n "; wsacleanup (); exit (0) ;}// int bytessend, left, idx = 0; int bytesrecv = socket_error; Char sendbuf [default_buffer] = ""; char recvbuf [default_buffer] = ""; while (true) {cout <"[send data to the server]:"; cin> sendbuf; // cout <sendbuf; left = strlen (sendbuf); // send data multiple times while (left> 0) {bytessend = Send (sockclient, & sendbuf [idx], left, 0); If (bytessend = 0) Exit (-1); If (bytessend = socket_error) {cout <"Send failed: "<wsagetlasterror () <Endl; exit (-1);} left-= bytessend; idx + = bytessend;} idx = 0; while (bytesrecv = = Socket_error) {bytesrecv = Recv (sockclient, recvbuf, default_buffer, 0); If (bytesrecv = 0 | bytesrecv = wsaeconnreset) {// The virtual circuit cout is stopped remotely <"the connection is closed! "<Endl; wsacleanup (); closesocket (sockclient); exit (-1);} If (bytesrecv <0) {cout <" no reply received "<Endl; exit (-1);} cout <"[received data from the server]:" <recvbuf <Endl;} bytesrecv = socket_error; memset (sendbuf, 0, default_buffer); memset (recvbuf, 0, default_buffer );}}

Server code:

Void starttcpserver () {wsadata WSA; Word version = makeword (2, 2); int ret; ret = wsastartup (version, & WSA); If (Ret! = No_error) {cout <"failed to initialize socket! "<Endl; return;} socket listensocket; // listening socketsocket clientsocket; // client D const char * ADR =" 127.0.0.1 "; const unsigned Port = 8088; listensocket = socket (af_inet, sock_stream, 0); sockaddr_in serveradrr; serveradrr. sin_family = af_inet; serveradrr. sin_port = htons (port); // serveradrr. sin_addr.s_un.s_addr = inet_addr (ADR); serveradrr. sin_addr.s_addr = inaddr_any; // The socket bound to the server and the server address ret = BIND (listensocket, (lpsockaddr) & serveradrr, sizeof (serveradrr); If (ret = socket_error) {cout <"failed to bind socket:" <wsagetlasterror () <Endl; return;} ret = listen (listensocket, 2); If (ret = socket_error) {cout <"listening port failed:" <wsagetlasterror () <Endl; return;} clientsocket = accept (listensocket, null, null); If (ret = socket_error) {cout <"listening port failed:" <wsagetlasterror () <Endl; return;} const unsigned size = 1 <8; char buffer [size]; // buffer = new char; memset (buffer, 0, sizeof (buffer); const char * STR = "connection to the server successful... "; strcpy_s (& buffer [0], sizeof (buffer), STR); ret = Send (clientsocket, buffer, sizeof (buffer), 0 ); cout <"Number of sent Bytes:" <RET <Endl; do {memset (buffer, 0, sizeof (buffer); ret = Recv (clientsocket, buffer, size, 0); If (Ret> 1) {cout <RET <Endl; cout <"client reply:" <buffer <Endl ;}} while (true );}
The preceding example implements TCP streaming socket programming in blocking mode in windows. The basic process is as follows:


Specific steps on the server side: 1. initialize the Winsock database before calling the socket, that is, load the DLL of the corresponding version. by calling the wsastartup function, fill in the information about the successfully loaded socket library version in the lpwsadata structure;

WSADATA lpWSAData;    WSAStartup(MAKEWORD(2,2),&lpWSAData);
2. create socket: After initialization, call the socket function to create a socket and return the socket handle. It is always used to identify the socket in subsequent communication. If the call fails, invalid_socket is returned. 3. bind socket to server address: after creating a socket for a specific protocol, bind the socket to a local address. The socket type is sockaddr, which is used to specify the socket binding address, including IP addresses and port numbers;
bind(sktConnect,(struct sockaddr far *)&sockaddrin,sizeof(sockaddrin));

4. server listening network: the socket uses the listen function to set the status bit to detect whether there are incoming connection requests, and then calls the accept function to prepare to receive client connection signals. When there is no connection request, service Process is blocked;

listen(sktConnect,1);    sktClient=accept(sktConnect,(struct sockaddr far *)&sockaddrin,& sockaddrlen);
5. send and receive data: Once the client socket receives a signal from the server, it indicates that the two sides have connected, either party can use the send/Write function and the Recv/read function to send or receive data to or from the other party;
send(sktClient,chrSend,10,0);recv(sktClient,chrReceive,10,0);
Specific steps of the client:

1. initialize and create the client Winsock:

First, the wsastartup function is used to fill in the wsadata structure. Then, the socket function is also called to create the socket of the client and assign a value to the sockaddr_in structure of the client. The address type and port number are the same as those of the server.

2. socket option settings:

Use the setsockopt function to set socket options, such as sending or receiving timeout settings, buffer capacity settings, and the ioctlsocket function to set socket I/O modes;

Int ret = ioctlsocket (sktclient, fionbio, (unsigned long *) & UL );
3. establish a connection between the two parties:
Connect (sktclient, (const struct sockaddr *) & sockaddrin, sizeof (sockaddrin ));

The client calls the connect function to send a connection request to the server. When the connection request arrives, the accept function of the blocked server generates a new byte stream socket and returns the sockaddr_in structure variable of the client, connect to the client using a socket with the client address, and then return the receiving signal to the client;

4. send and receive data

5. Disable socket and Winsock logout:

The server and client can call the closesocket function to disable all sending and receiving operations on the socket, cancel the socket, and interrupt the connection. At the same time, after the dynamic link library of the Winsock service is used, the application must call the wsacleanup function to unregister it and release the allocated resources.


The following describes some basic concepts: 1. Socket)

It is the basic component of the network. It is a communication endpoint that can be named and addressable. Each socket in use has its type and a process connected to it. The socket exists in the communication area (also known as address cluster. The socket only exchanges data with the socket in the same region (a specific and conversion process must be executed across regions ). In Windows, sockets only support a single communication domain.

A socket is an integer of the int type, similar to a file descriptor or handle.

Sockets are divided into Stream Sockets (sock_stream) and datagram Sockets (sock_dgram ). Stream socket provides bidirectional ordered, non-repetitive, and non-record-free data stream service, which is suitable for processing large amounts of data. It is connection-oriented. A path must be created before both parties exchange data. If the TCP protocol is used, set the socket to stream.

The datagram socket supports two-way data streams, but it does not guarantee the reliability, orderliness, and repeatability of transmission. It is connectionless. Applicable to UDP.

2. socket address (sockaddr and sockaddr_in)

The structure of struct sockaddr is as follows:
struct sockaddr{  u_short  sa_family;  char     sa_data[14];};

Sa_family is the abbreviation of socket address family, indicating the address type. af_inet indicates that the socket is in the Internet domain. The other 14 bytes are used to describe the address. This is a general structure. In fact, when we specify sa_family = af_inet, the form of sa_data is fixed: The frontend 2 bytes are used to record 16-bit ports, the next 4 bytes are used to record the 32-bit IP address, and the last 8 bytes are cleared to zero. The address structure varies with the selected protocol. Therefore, another sockaddr_in structure with the same size as the address structure is more commonly used, the sockaddr_in structure is used to identify the addresses under the TCP/IP protocol. sockaddr_in can be forcibly converted to sockaddr. The structure format of sockaddr_in is as follows:

Struct sockaddr_in {short sin_family; unsigned short sin_port; // port struct in_addr sin_addr; char sin_zero [8];};
In_addr is obviously an Internet address, and its structure is as follows:
struct in_addr{    unsigned long s_addr;};

S_addr is an IP address. You can use the inet_addr function to convert a string similar to "127.0.0.1" to long. 3. The Winsock startup and termination services are implemented in the form of dynamic link library Winsock DLL. Therefore, you must first call the wsastartup function to initialize Winsock DLL, set the version number, and allocate necessary resources. The following is a prototype of the wsastartup function:

Int wsastartup (word wversionrequested, lpwsadata); where wversionrequested is used to specify the version of the Winsock database, usually high bytes specify the secondary version, and low bytes specify the primary version. Then, use macro makeword (x, y) (X is a high byte, and Y is a low byte) to obtain the correct value of wversionrequested. The lpwsadata parameter is a pointer to the lpswsadata structure, which contains information about the library version. The format is as follows:
Typedef struct wsadata {word wversion; // Winsock version word whightversion; char szdescription [wsadescription_len + 1]; char szsystemstatus [wsasys_status_len + 1]; unsigned short imaxsocket; // The maximum length of the opened socket unsigned short imaxudpdg; // the maximum length of the opened datagram char far * lpvendorinfo;} wsadata, * lpwsadata;
The following is the UDP protocol for sending and receiving messages: UDP. h
# Pragma once # include <winsock2.h> # include <tchar. h> # include <process. h ># include <string >#include <iostream> # pragma comment (Lib, "ws2_32.lib") using namespace STD; // clients // UDP client // ----------------------------------------------- const char * default_host = "127.0.0.1"; const int default_port = 8088; struct sockfd {int FD; sockaddr * ADDR; sockfd (): FD (), ADDR (null ){}~ Sockfd () {ADDR = NULL ;}; int initsocket () {wsadata WSA; If (wsastartup (0x202, & WSA )! = No_error) {cerr <"initialization socket error" <Endl; Return-1;} return 0 ;} // notify // send all the buffer in a loop // ------------------------------------------------- int sendall (sockfd * SC, const char * buffer, size_t sz) {int err = 0; int Sen = 0; while (true) {err = sendto (SC-> FD, buffer, SZ-Sen, 0, SC-> ADDR, sizeof sockaddr_in); If (ERR <= 0) {return err;} Sen + = err; If (Sen = sz) {cout <"Send message: "<buffer <" Total "<SZ <" Byte "<Endl; break;} return Sen;} int readall (sockfd * SC, char * buffer, size_t sz) {int err = 0; int Len = sizeof sockaddr_in; while (true) {err = recvfrom (SC-> FD, buffer, SZ, 0, SC-> ADDR, & Len); If (ERR <= 0) {// cerr <"" <Endl; return err;} break;} return err ;}

Client class:

# Pragma once # include ".. /common/UDP. H "// The message sending thread unsigned winapi sendth (lpvoid lparam) {sockfd * SC = reinterpret_cast <sockfd *> (lparam); unsigned char head [2]; char buffer [1024]; while (! Cin. bad () {memset (buffer, 0, sizeof buffer); CIN> buffer; // first send the message header size_t Len = strlen (buffer ); // the actual length of the message unsigned char head [2]; // up to 2 bytes can be expressed (1 <16)-1 head [0] = (LEN> 8) & 0xff; // low head [1] = Len & 0xff; // high int r = sendall (SC, (char *) Head, 2); If (r <0) {cerr <"failed to send the header" <Endl; Return-1 ;}// resend the Message Subject r = sendall (SC, buffer, Len ); if (r <0) {cerr <"failed to send message" <Endl; Return-1 ;}} return 0 ;} // The thread that receives the message unsigned winapi recvth (lpvoid lparam) {sockfd * SC = reinterpret_cast <sockfd *> (lparam); While (true) {unsigned char head [2]; memset (Head,); If (readall (SC, (char *) Head, 2) = 0) {break ;} size_t Len = (head [0] <8) | head [1]; If (LEN> 0) {// receives the message char * temp = new char [Len + 1]; memset (temp, 0, Len + 1); readall (SC, temp, Len ); temp [Len] = '\ 0'; cout <"received from the server:" <temp <"Total: "<Len <" Byte "<Endl; Delete temp ;}return 0;} int _ tmain (INT ARGs, tchar * argv []) {initsocket (); socket clientsock = socket (af_inet, sock_dgram, 0); sockaddr_in ADDR; memset (& ADDR, 0, sizeof ADDR); ADDR. sin_family = af_inet; ADDR. sin_addr.s_addr = inet_addr (default_host); ADDR. sin_port = htons (default_port); sockfd * SC = new sockfd; SC-> FD = clientsock; SC-> ADDR = reinterpret_cast <lpsockaddr> (& ADDR ); cout <"------------------ the UDP client has started -----------------" <Endl; // enable the thread unsigned thid; handle send = (handle) _ beginthreadex (null, 0, sendth, SC, 0, & thid); handle recive = (handle) _ beginthreadex (null, 0, recvth, SC, 0, & thid); waitforsingleobject (send, infinite); waitforsingleobject (recive, infinite); closehandle (send); closehandle (recive); Delete SC; closesocket (clientsock); wsacleanup (); System ("pause"); Return 0 ;}

Server: receives client messages and returns them to the client.

# Pragma once # include ".. /common/UDP. H "Void sendmsg (sockfd * SC, const char * buffer) {unsigned char head [2]; memset (Head, 0, 2); size_t Len = strlen (buffer ); head [0] = (LEN> 8) & 0xff; head [1] = Len & 0xff; int r = sendall (SC, (char *) Head, 2 ); if (r <0) {cerr <"failed to send the header" <Endl;} r = sendall (SC, buffer, Len); If (r <0) {cerr <"failed to send message" <Endl ;}} void recvmsg (sockfd * SC) {unsigned char head [2]; while (true) {// receive message header memset (Head,); If (readall (SC, (char *) Head, 2) = 0) {break ;} size_t Len = head [0] <8 | head [1]; char * MSG = new char [Len + 1]; readall (SC, MSG, Len ); MSG [Len] = '\ 0'; cout <"receives a message from the client:" <MSG <"Total" <Len <"Byte" <Endl; // return the message to the client sendmsg (SC, MSG); Delete MSG ;}} int _ tmain (INT argc, tchar * argv []) {initsocket (); socket recivesocket = socket (af_inet, sock_dgram, 0); sockaddr_in serveraddr; serveraddr. sin_family = af_inet; serveraddr. sin_addr.s_addr = inet_addr (default_host); serveraddr. sin_port = htons (default_port); int iresult = BIND (recivesocket, reinterpret_cast <lpsockaddr> (& serveraddr), sizeof serveraddr); If (iresult = socket_error) {cerr <"failed to bind port" <Endl;} sockfd * SC = new sockfd; SC-> FD = recivesocket; SC-> ADDR = reinterpret_cast <lpsockaddr> (& serveraddr); cout <"------------------ the UDP server has started -----------------" <Endl; // start to accept the message recvmsg (SC ); delete SC; closesocket (recivesocket); wsacleanup (); System ("pause"); Return 0 ;}
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.