基于TCP(面向连接)socket编程

一.基于TCP(面向连接)的socker编程的服务器端程序流程如下:

(1)    创建套接字(socket

(2)    将套接字绑定到一个本地地址和端口上(bind

(3)    将套接字设置为监听模式,准备接收客户请求(listen

(4)    等待客户请求的到来;当客户请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept

(5)    用返回的套接字和客户端进行通信(send/recv

(6)    返回等待另一个客户请求

(7)    关闭套接字

. 基于TCP(面向连接)socket编程的客户端程序流程如下:

1)创建套接字(socket

2)向服务器发出连接请求(connect

3)和服务器端进行通信(send/recv

4)关闭套接字

 

 

例子:

服务器端:

 
  
  1. //服务器端  
  2.  
  3. #include <WINSOCK2.H>  
  4. #include <stdio.h>  
  5.  
  6. void main()  
  7. {  
  8. /********************************************************    在利用套接字编程时,首先要加载套接字,通过WSAStartup函数来实现.  
  9.     函数原型:int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);  
  10.        (1) wVersionRequested:用来指定准备加载的Winsock库的版本,高位字节指定所需的winsock库的副版本,低位字节则是主版本。可以利用MAKEWORD(x, y)宏来获得wVersionRequested的正确值。  
  11.         (2) lpWSAData是指向WSADATA结构的指针,WSAStartup函数用其加载的库版本有关的信息填充在这个结构中  
  12. ***********************************************/ 
  13.       
  14.     WORD wVersionRequested;  
  15.     WSADATA wsaData;  
  16.     int err;  
  17.  
  18.     wVersionRequested = MAKEWORD(1, 1);  
  19.     err = WSAStartup(wVersionRequested, &wsaData);  
  20.  
  21.     if(err != 0)  
  22.     {  
  23.         //加载失败  
  24.         return;  
  25.     }  
  26.  
  27.     if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)  
  28.     {  
  29.         //释放为该应用程序分配的资源,终止对WinSock动态库的使用  
  30.         WSACleanup();  
  31.         return;  
  32.     }  
  33.  
  34.     /*************************************************************************************/ 
  35.     /*  加载套接字库之后,调用socket函数创建套接字  
  36.     函数原型:SOCKET socket(int af, int type,  int protocol);  
  37.     (1):af参数指定地址族,对于TCP/IP协议的套接字,它只能是AF_INET(也可以写成PF_INET)  
  38.     (2):type参数,指定socket类型,对于1.1版本的socket,只支持两种:SOCK_STREAM, SOCK_DGRAM  
  39.     (3):protocol参数是与特定的地址家族相关的协议,推荐指定为0  
  40.     返回值:如果socket函数调用成功,返回一个新的socket数据类型的套接字描述符,如果调用失败,  
  41.             此函数返回一个INVALID_SOCKET值,错误信息通过WSAGetLastError函数返回  
  42.     */ 
  43.     /************************************************************************************/ 
  44.       
  45.       
  46.     //创建用于监听的套接字  
  47.     SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);  
  48.  
  49.  
  50.     /**************************************************************************************************************/ 
  51.     /* 通过bind函数将套接字绑定到本地的某个地址和端口上  
  52.        函数原型:int bind(SOCKET s, const struct sockaddr FAR *name, int namelen);  
  53.        (1)s参数指定要绑定的套接字。  
  54.        (2)name参数指定了该套接字的本地地址信息,此为一个指向sockaddr结构的指针变量  
  55.        (3)namelen参数指定该地址结构的长度  
  56.        备注1:struct sockaddr{  
  57.                 u_short sa_family;  //指定地址家族,对TCP/IP协议的套接字,必须为AF_INET  
  58.                 char    sa_data[14]; //仅表示要求一块内存分配区,起到占位的作用,该区域中指定与协议相关的具体地址信息  
  59.                 };  
  60.         在基于TCP/IP的socket编程中,使用sockaddr_in结构替换sockaddr  
  61.              struct sockaddr_in{  
  62.                 short             sin_family; //指定地址家族,对TCP/IP协议的套接字,必须为AF_INET  
  63.                 unsigned short    sin_port;   //指定分配给套接字的端口,必须为网络字节序  
  64.                 struct   in_addr  sin_addr;   //指定套接字的主机IP地址,必须为网络字节序  
  65.                 char              sin_zero[8];//起占位作用  
  66.                 };  
  67.                 其中sin_addr成员的类型是in_addr,该结构定义如下:  
  68.                 struct in_addr{  
  69.                     union {  
  70.                        struct { u_char s_b1,s_b2,s_b3,s_b4; }   S_un_b; //Address of the host formatted as four u_chars.   
  71.                        struct { u_short s_w1,s_w2; }            S_un_w; //Address of the host formatted as two u_shorts.   
  72.                        u_long                                   S_addr; //Address of the host formatted as a u_long.   
  73.                        } S_un;  
  74.                 };  
  75.  
  76.         备注2:(1)  u_short htons(u_short hostshort );  
  77.                     此函数用于将一个u_short类型的值从主机字节顺序转换为TCP/IP网络字节顺序。  
  78.                (2)  u_long  htonl(u_long  hostlong  );  
  79.                     此函数用于将一个u_long类型的值从主机自己顺序转换为TCP/IP网络字节顺序。  
  80.                (3)  unsigned long inet_addr(const char   FAR *cp);  
  81.                     此函数需要一个字符串作为其参数,该字符串指定了以点分十进制格式表示的IP地址,返回一个适合分配给S_addr的u_long类型的数值  
  82.                (4)  char FAR * inet_ntoa(struct   in_addr in);  
  83.                     此函数接受一个in_addr结构体类型的参数并返回一个以点分十进制格式表示的IP地址字符串  
  84.     */ 
  85.     /******************************************************************************************************************/ 
  86.  
  87.     SOCKADDR_IN addrSrv;  
  88.     addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//将u_short类型的值从主机字节序转换位网络字节序  
  89.     addrSrv.sin_family = AF_INET;  
  90.     addrSrv.sin_port = htons(6001); //将u_long类型的值从主机字节序转换为网络字节序  
  91.     //绑定套接字  
  92.     bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));  
  93.  
  94.  
  95.     /************************************************************************/ 
  96.     /* 将指定的套接字设置为监听模式  
  97.        函数原型:int listen(SOCKET s,    int backlog);  
  98.        (1): s参数是套接字描述符  
  99.        (2): backlog参数是等待连接队列的最大长度  
  100.     */ 
  101.     /************************************************************************/ 
  102.     //将套接字设为监听模式,准备接收客户请求  
  103.     listen(sockSrv, 5);  
  104.  
  105.     SOCKADDR_IN addrClient;  
  106.     int len = sizeof(SOCKADDR);  
  107.  
  108.     while (1)  
  109.     {  
  110.         /************************************************************************/ 
  111.         /* 利用accept函数接受客户端发送的请求  
  112.         函数原型:SOCKET accept(SOCKET s, struct sockaddr FAR *addr,  int FAR *addrlen);  
  113.         (1) s参数是套接字描述符,该套接字已经通过listen函数将其设置为监听状态  
  114.         (2) addr参数指向一个缓冲区的指针,该缓冲区用来接收连接实体的地址,即客户端的IP地址和端口  
  115.         (3) addrlen参数指向一个整型的指针,返回包含地址信息的长度  
  116.         */ 
  117.         /************************************************************************/ 
  118.  
  119.         //等待客户请求  
  120.         SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrClient, &len);  
  121.           
  122.         char sendBuf[100];  
  123.         sprintf(sendBuf,"Welcome %s to xidian", inet_ntoa(addrClient.sin_addr));  
  124.         printf("Welcome %s to xidian\n", inet_ntoa(addrClient.sin_addr));  
  125.  
  126.         //发送数据  
  127.         send(sockConn, sendBuf, strlen(sendBuf)+1, 0);  
  128.  
  129.         char recvBuf[100]={'0'};  
  130.         //接收数据  
  131.         recv(sockConn, recvBuf, 100, 0);  
  132.  
  133.         //打印接收的数据  
  134.         printf("%s\n", recvBuf);  
  135.         //关闭套接字  
  136.         closesocket(sockConn);  
  137.     }  
  138.       

 客户端:

 

 
  
  1. //TCP客户端  
  2.  
  3. #include <WINSOCK2.H>  
  4. #include <stdio.h>  
  5.  
  6. void  main()  
  7. {  
  8.     //加载套接字库  
  9.     WORD wVersionRequested;  
  10.     WSADATA wsaData;  
  11.     int err;  
  12.  
  13.     wVersionRequested = MAKEWORD(1, 1);  
  14.       
  15.     err = WSAStartup(wVersionRequested, &wsaData);  
  16.     if (err != 0)  
  17.     {  
  18.         return;  
  19.     }  
  20.  
  21.     if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)  
  22.     {  
  23.         WSACleanup();  
  24.         return;  
  25.     }  
  26.  
  27.  
  28.     //创建套接字  
  29.     SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);  
  30.  
  31.     //要连接服务器的信息,注意使用的是网络字节序  
  32.     SOCKADDR_IN addrSrv;  
  33.     addrSrv.sin_family = AF_INET;  
  34.     addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  
  35.     addrSrv.sin_port = htons(6001);  
  36.  
  37.  
  38.     //向服务器发送连接请求  
  39.     connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));  
  40.  
  41.     //接收数据  
  42.     char recvBuf[100]={'0'};  
  43.  
  44.     recv(sockClient, recvBuf, 100, 0);  
  45.  
  46.     printf("%s\n", recvBuf);  
  47.  
  48.     //发送数据  
  49.     send(sockClient, "This is a client test", strlen("This is a client test")+1, 0);  
  50.  
  51.     //关闭套接字  
  52.     closesocket(sockClient);  
  53.     WSACleanup();  
  54.