socket基础知识

一  SOCKET相关结构

  1  WSADATA  用于初始化WINSOCK

[cpp] view plaincopy

  1. WSADATA WSaData;    
  2. int err;  
  3. err = WSAStartup(0x0202, &WSaData);  
  4. if (err == SOCKET_ERROR)  
  5. {      
  6.     AfxMessageBox(L"初始化Socket失败");  
  7.     exit(0);  
  8.     return -1;  
  9. }  


  2  Socket address, internet style.

[cpp] view plaincopy

  1. struct sockaddr_in {  
  2.         short   sin_family;  
  3.         u_short sin_port;  
  4.         struct  in_addr sin_addr;  
  5.         char    sin_zero[8];  
  6. };  

  3  Internet address 

[cpp] view plaincopy

  1. struct in_addr {  
  2.         union {  
  3.                 struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;  
  4.                 struct { u_short s_w1,s_w2; } S_un_w;  
  5.                 u_long S_addr;  
  6.         } S_un  
扫描二维码关注公众号,回复: 3591255 查看本文章

二 SOCKET相关转换函数

  1  inet_addr

  This function converts a string containing an (Ipv4) Internet Protocol dotted address into a proper address for thein_addr structure

  将IP地址从 点数格式转换成无符号长整型

   net_addr()返回的地址已经是网络字节格式,无需再调用 函数htonl()

[cpp] view plaincopy

  1. unsigned long inet_addr(  
  2.   const char FAR* cp  
  3. );  

[cpp] view plaincopy

  1. struct sockaddr_in  serv_addr; //服务器端SOCKET地址  
  2. serv_addr.sin_addr.s_addr = inet_addr("192.221.5.10″);  


  2  inet_ntoa

  The inet_ntoa function converts an (Ipv4) Internet network address into a string in Internet standard dotted format.

  If no error occurs, inet_ntoa returns a character pointer to a static buffer containing the text address in standard ".'' notation. Otherwise, it returns NULL.

  将网络IP地址转换成标准的点格式IP地址

 它返回的是一个指向一个字符的 指针。它是一个由inet_ntoa()控制的静态的固定的指针,所以每次调用 inet_ntoa(),它就将覆盖上次调用时所得的IP地址

[cpp] view plaincopy

  1. char* FAR inet_ntoa(  
  2.   struct   in_addr in  
  3. );  

[cpp] view plaincopy

  1. char *a1, *a2;  
  2. a1 = inet_ntoa(ina1.sin_addr); /* 这是198.92.129.1 */  
  3. a2 = inet_ntoa(ina2.sin_addr); /* 这是132.241.5.10 */  
  4. printf(“address 1: %s “,a1);  
  5. printf(“address 2: %s “,a2);  
  6. 输出如下:  
  7. address 1: 132.241.5.10  
  8. address 2: 132.241.5.10  

假如你需要保存这个IP地址,使用strcopy()函数来指向你自己的字符指针。

  3  ntohs, ntohl, htons,htonl

    ntohs:

[cpp] view plaincopy

  1. u_short ntohs(  
  2.   u_short netshort  
  3. );  

   This function converts a u_short from TCP/IP network byte order to host byte order, which is little-endian on Intel processors. 

   无符号短整形数从网络字节顺序转换为主机字节顺序

  htons:

[cpp] view plaincopy

  1. u_short htons(  
  2.   u_short hostshort  
  3. );  

The htons function converts a u_short from host to TCP/IP network byte order (which is big-endian).

将主机的无符号短整形数转换成网络字节顺序

  ntohl:

[cpp] view plaincopy

  1. u_long ntohl(  
  2.   u_long netlong  
  3. );  

This function converts a u_long from TCP/IP network order to host byte order, which is little-endian on Intel processors.

 将一个无符号长整形数从网络字节顺序转换为主机字节顺序

  htonl:

[cpp] view plaincopy

  1. u_long htonl(  
  2.   u_long hostlong  
  3. );  

This function converts a u_long from host to TCP/IP network byte order, which is big-endian

将主机的无符号长整形数转换成网络字节顺序


 

 
 

三  SOCKET相关函数

1 创建socket

[cpp] view plaincopy

  1. SOCKET socket(  
  2.   int af,  
  3.   int type,  
  4.   int protocol  
  5. );  

This function creates a socket that is bound to a specific service provider.

第一个参数为int af,代表网络地址族,目前只有一种取值是有效的,即AF_INET,代表internet地址族;

第二个参数为int type,代表网络协议类型,SOCK_DGRAM代表UDP协议,SOCK_STREAM代表TCP协议;

第三个参数为int protocol,指定网络地址族的特殊协议,目前无用,赋值0即可。

返回值为SOCKET,若返回INVALID_SOCKET则失败。

[cpp] view plaincopy

  1. SOCKET g_socket = socket(AF_INET, SOCK_STREAM,0);  

2 bind() 绑定IP地址

 This function associates a local address with a socket.

 bind函数用来将一个套接字绑定到一个IP地址。一般只在服务方(即数据发送方)调用,很多函数会隐式的调用bind函数

[cpp] view plaincopy

  1. int bind(  
  2.   SOCKET s,  
  3.   const struct sockaddr FAR* name,  
  4.   int namelen  
  5. );  

  If no error occurs, this function returns zero. If an error occurs, it returns SOCKET_ERROR

  通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器
  而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合

  这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个

3 listen监听

  The listen function places a socket in a state in which it is listening for an incoming connection.

 从服务方监听客户方的连接。同一个套接字可以多次监听。

[cpp] view plaincopy

  1. int listen(  
  2.   SOCKET s,  
  3.   int backlog  
  4. );  


  listen函数的第一个参数即为要监听的socket描述字, 第二个参数为相应socket可以排队的最大连接个数。

  socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

  listen()在执行调用过程中可为没有调用过bind()的套接字s完成所必须的连接,并建立长度为backlog的请求连接队列。

  调用listen()是服务器接收一个连接请求的四个步骤中的第三步。它在调用socket()分配一个流套接字,且调用bind()给s赋于一个名字之后调用,而且一定要在accept()之前调用。 

4 connect()连接

  The connect function establishes a connection to a specified socket.

[cpp] view plaincopy

  1. int connect(  
  2.   SOCKET s,  
  3.   const struct sockaddr* name,  
  4.   int namelen  
  5. );  


  s            [in] Descriptor identifying an unconnected socket.  客户端SOCKET

  name   [in] Name of the socket in the sockaddr structure to which the connection should be established.    服务器SOCKET地址

  nameLen  Length of name, in bytes

  

  connect是客户方连接服务方的函数,而accept是服务方同意客户方连接的函数。

 这两个配套函数分别在各自的程序中被成功调用后就可以收发数据了。

[cpp] view plaincopy

  1. SOCKET g_socket = socket(AF_INET, SOCK_STREAM,0);  
  2. if (g_socket < 0)      
  3. {  
  4.     MessageBox(_T("socket() failed--do you have TCP/IP newworking installed?"),_T("Error"),0);  
  5.     exit(0);  
  6.     return -1;  
  7. }  
  8.   
  9. struct sockaddr_in  serv_addr; //服务器端SOCKET地址  
  10. memset(&serv_addr, 0, sizeof(serv_addr));  
  11. serv_addr.sin_family    = AF_INET;   
  12. serv_addr.sin_addr.s_addr=inet_addr("192.221.5.10");  
  13. serv_addr.sin_port = htons(4000);  
  14.   
  15.   
  16.   
  17.   
  18. int nFlag = connect(g_socket, (struct sockaddr *) &serv_addr,sizeof(serv_addr));  
  19. if ( nFlag< 0)  
  20. {       
  21.     int     err = WSAGetLastError();//0  
  22.     closesocket(g_socket);  
  23.     WSACleanup();  
  24.     AfxMessageBox(L"无法连接服务端");  
  25.     exit(0);  
  26.     return -1;   
  27. }  


5 accept()函数

The accept function permits an incoming connection attempt on a socket

 服务器同意客户端相连

[cpp] view plaincopy

  1. SOCKET accept(  
  2.   SOCKET s,  
  3.   struct sockaddr* addr,  
  4.   int* addrlen  
  5. );  


  s           [in] Descriptor that identifies a socket that has been placed in a listening state with thelisten function

  addr    [OUT] Optional pointer to a buffer that receives the address of the connecting entity, as known to the communications layer

  addrlen  [in, out] Optional pointer to an integer that contains the length ofaddr

If no error occurs, accept returns a value of type SOCKET that is a descriptor for the new socket. This returned value is a handle for the socket on which the actual connection is made.

Otherwise, a value of INVALID_SOCKET is returned, and a specific error code can be retrieved by callingWSAGetLastError.

accept函数的第一个参数为服务器的socket描述字

第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址

第三个参数为协议地址的长度

如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。

注:

  accept的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字

  而accept函数返回的是已连接的socket描述字

  一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在

  内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。

  TCP服务器端依次调用socket()bind()listen()之后,就会监听指定的socket地址了。

  TCP客户端依次调用socket()connect()之后就想TCP服务器发送了一个连接请求

  TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求

  这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。

[cpp] view plaincopy

  1. #include <stdio.h>  
  2. #include "winsock2.h"  
  3.   
  4. void main() {  
  5.   
  6.   //----------------------  
  7.   // Initialize Winsock.  
  8.   WSADATA wsaData;  
  9.   int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);  
  10.   if (iResult != NO_ERROR)  
  11.     printf("Error at WSAStartup()\n");  
  12.   
  13.   //----------------------  
  14.   // Create a SOCKET for listening for  
  15.   // incoming connection requests.  
  16.   SOCKET ListenSocket;  
  17.   ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
  18.   if (ListenSocket == INVALID_SOCKET) {  
  19.     printf("Error at socket(): %ld\n", WSAGetLastError());  
  20.     WSACleanup();  
  21.     return;  
  22.   }  
  23.   
  24.   //----------------------  
  25.   // The sockaddr_in structure specifies the address family,  
  26.   // IP address, and port for the socket that is being bound.  
  27.   sockaddr_in service;  
  28.   service.sin_family = AF_INET;  
  29.   service.sin_addr.s_addr = inet_addr("127.0.0.1");  
  30.   service.sin_port = htons(27015);  
  31.   
  32.   if (bind( ListenSocket,   
  33.     (SOCKADDR*) &service,   
  34.     sizeof(service)) == SOCKET_ERROR) {  
  35.     printf("bind() failed.\n");  
  36.     closesocket(ListenSocket);  
  37.     return;  
  38.   }  
  39.   
  40.   //----------------------  
  41.   // Listen for incoming connection requests.  
  42.   // on the created socket  
  43.   if (listen( ListenSocket, 1 ) == SOCKET_ERROR)  
  44.     printf("Error listening on socket.\n");  
  45.   
  46.   //----------------------  
  47.   // Create a SOCKET for accepting incoming requests.  
  48.   SOCKET AcceptSocket;  
  49.   printf("Waiting for client to connect...\n");  
  50.   
  51.   //----------------------  
  52.   // Accept the connection.  
  53.   while(1) {  
  54.     AcceptSocket = SOCKET_ERROR;  
  55.     while( AcceptSocket == SOCKET_ERROR ) {  
  56.       AcceptSocket = accept( ListenSocket, NULL, NULL );  
  57.     }  
  58.     printf("Client connected.\n");  
  59.     ListenSocket = AcceptSocket;  
  60.     break;  
  61.   }  
  62.   
  63.   WSACleanup();  
  64.   return;  
  65. }  


6 Send发送数据 

The send function sends data on a connected socket.

[cpp] view plaincopy

  1. int send(  
  2.   SOCKET s,  
  3.   const char* buf,  
  4.   int len,  
  5.   int flags  
  6. );  


  s          [in] Descriptor identifying a connected socket.

  buf     [in] Buffer containing the data to be transmitted.

  len     [in] Length of the data in buf, in bytes.

 flags  [in] Indicator specifying the way in which the call is made.

 If no error occurs, send returns the total number of bytes sent, which can be less than the number indicated bylen. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved

[cpp] view plaincopy

  1. #include <stdio.h>  
  2. #include "winsock2.h"  
  3.   
  4. void main() {  
  5.   //----------------------  
  6.   // Initialize Winsock  
  7.   WSADATA wsaData;  
  8.   int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);  
  9.   if (iResult != NO_ERROR)  
  10.     printf("Error at WSAStartup()\n");  
  11.   
  12.   //----------------------  
  13.   // Create a SOCKET for connecting to server  
  14.   SOCKET ConnectSocket;  
  15.   ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
  16.   if (ConnectSocket == INVALID_SOCKET) {  
  17.     printf("Error at socket(): %ld\n", WSAGetLastError());  
  18.     WSACleanup();  
  19.     return;  
  20.   }  
  21.   
  22.   //----------------------  
  23.   // The sockaddr_in structure specifies the address family,  
  24.   // IP address, and port of the server to be connected to.  
  25.   sockaddr_in clientService;   
  26.   clientService.sin_family = AF_INET;  
  27.   clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );  
  28.   clientService.sin_port = htons( 27015 );  
  29.   
  30.   //----------------------  
  31.   // Connect to server.  
  32.   if ( connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR) {  
  33.     printf( "Failed to connect.\n" );  
  34.     WSACleanup();  
  35.     return;  
  36.   }  
  37.   
  38.   //----------------------  
  39.   // Declare and initialize variables.  
  40.   int bytesSent;  
  41.   int bytesRecv = SOCKET_ERROR;  
  42.   char sendbuf[32] = "Client: Sending data.";  
  43.   char recvbuf[32] = "";  
  44.   
  45.   //----------------------  
  46.   // Send and receive data.  
  47.   bytesSent = send( ConnectSocket, sendbuf, strlen(sendbuf), 0 );  
  48.   printf( "Bytes Sent: %ld\n", bytesSent );  
  49.   
  50.   while( bytesRecv == SOCKET_ERROR ) {  
  51.     bytesRecv = recv( ConnectSocket, recvbuf, 32, 0 );  
  52.     if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) {  
  53.       printf( "Connection Closed.\n");  
  54.       break;  
  55.     }  
  56.     printf( "Bytes Recv: %ld\n", bytesRecv );  
  57.   }  
  58.   
  59.   WSACleanup();  
  60.   return;  
  61. }  


7 recv 接收函数

The recv function receives data from a connected or bound socket.

[cpp] view plaincopy

  1. int recv(  
  2.   SOCKET s,  
  3.   char* buf,  
  4.   int len,  
  5.   int flags  
  6. );  

  s          [in] Descriptor identifying a connected socket.

  buf     [out] The buffer for incoming data

  len     [in] The length, in bytes, of buf

 flags  [in] Indicator specifying the way in which the call is made.

  If no error occurs, recv returns the number of bytes received. If the connection has been gracefully closed, the return value is zero. Otherwise, a value of SOCKET_ERROR is returned

8 关闭SOCKET

[cpp] view plaincopy

  1. int closesocket(  
  2.   SOCKET s  
  3. );  


  If no error occurs, closesocket returns zero. Otherwise, a value of SOCKET_ERROR

猜你喜欢

转载自blog.csdn.net/shenhua969/article/details/24983279
今日推荐