• 在windows下使用C语言实现回声服务器和客户端(socket)


      记录一下在windows平台实现基本的socket编程,实现一个简易的回声服务器和客户端,废话不多说,直接上代码,里面有详尽的注释。

    操作系统:win10 64位

    编辑器:vscode,需要安装c/c++插件。

    编译器:MinGw编译器

      服务器:

      1 #include <stdio.h>
      2 #include <winsock2.h>
      3 #pragma comment(lib,"ws2_32.lib")
      4 
      5 #define PORT 6666
      6 
      7 int main()
      8 {
      9     WSADATA wsaData = {0}; //定义一个结构体,用来接收函数给的参数
     10     int err = -1;
     11     //第一步:定义我们需要的winsock的版本,这里是2.2版本(目前最高的版本号)
     12     err = WSAStartup(MAKEWORD(2,2), &wsaData);
     13     if(0 != err) //返回非0 ,代表出错
     14     {
     15         printf("failed with error:%d
    ", err);
     16         system("pause");
     17         return 1;
     18     }
     19     //第二部:查看当前系统支持的版本,如果不支持我们上面定义的版本就用不了
     20     if(LOBYTE(wsaData.wVersion)!=2 || HIBYTE(wsaData.wVersion)!=2)
     21     {
     22         printf("system not support for this version
    ");
     23         WSACleanup(); //释放系统资源
     24         system("pause");
     25         return 1;
     26     }
     27     else
     28     {
     29         printf("The WinSock 2.2 dll was found
    ");
     30     }
     31     //第三步:开始创建套接字
     32     SOCKET server = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
     33     if(INVALID_SOCKET == server)
     34     {
     35         printf("create socket failed with error:%d
    ",WSAGetLastError());
     36         WSACleanup();
     37         system("pause");
     38         return 1;
     39     }
     40     //第四步:准备结构体,绑定socket
     41     SOCKADDR_IN addr = {};
     42     addr.sin_family = AF_INET;
     43     addr.sin_port = htons(PORT); //将本地字节序转换成网络字节序
     44     addr.sin_addr.S_un.S_addr = INADDR_ANY;
     45     //如果需要指定IP,可以这样
     46     //addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
     47     if(SOCKET_ERROR == bind(server,(SOCKADDR*)&addr,sizeof(addr))) //成功返回0
     48     {
     49         printf("bind socket failed with error:%d
    ",WSAGetLastError());
     50         closesocket(server);
     51         WSACleanup();
     52         system("pause");
     53         return 1;
     54     }
     55     //第五步:监听
     56     if(SOCKET_ERROR == listen(server,SOMAXCONN)) //成功返回0
     57     {
     58         printf("listen socket failed with error:%d
    ",WSAGetLastError());
     59         closesocket(server);
     60         WSACleanup();
     61         system("pause");
     62         return 1;
     63     }
     64     //第六步,等待连接
     65     SOCKADDR_IN cli_addr = {};
     66     int len = sizeof(cli_addr);
     67     printf("all is okay,waitting for client......
    ");
     68     while(1) //因为可以接收很多的客户,这里使用无限循环
     69     {
     70         // 这一步将会阻塞,直到有客户端连接进来(接客)
     71         SOCKET cli = accept(server,(SOCKADDR*)&cli_addr,&len);
     72         //这一步可以优化,用线程来做,主线程只负责接客,子线程来服务客人(有效的连接)。
     73         if(INVALID_SOCKET == cli)
     74         {
     75             printf("invalide socket,error:%d
    ",WSAGetLastError());
     76             closesocket(server);
     77             WSACleanup();
     78             system("pause");
     79             return 1;
     80         }
     81         //客户信息有效,打印下看看吧
     82         printf(">>client$	%s:%d connected!
    ",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));
     83 
     84         //第七步:开始通讯,这里写一个回声服务器(将收到的数据,原数发回给客户端)
     85         char buff[MAXBYTE] = {}; //存储客户端发来的信息
     86         int bufflen = 0;
     87         do  //客户端可能会发送多次数据,这里暂使用无限循环
     88         {
     89             //每次接收数据前,需要将上一次接收的缓冲区数据清空
     90             ZeroMemory(buff,sizeof(buff)); //该函数底层调用的memset函数
     91             bufflen = recv(cli,buff,sizeof(buff),0);
     92             if(bufflen == 0)  //recv函数可以接受0个参数,代表对方关闭连接了
     93             {
     94                 printf("connection closed!
    ");
     95             }
     96             else if (SOCKET_ERROR == bufflen)
     97             {
     98                 printf("recv failed with error:%d
    ",WSAGetLastError());
     99             }
    100             else //接收到了数据
    101             {
    102                 buff[bufflen] = '';
    103                 printf("received:%s
    ",buff);
    104                 //send函数可以发送大于等于0的数据
    105                 int len = send(cli,buff,bufflen,0);
    106                 if(SOCKET_ERROR == len)
    107                 {
    108                     printf("send failed with error:%d
    ",WSAGetLastError());
    109                     break;
    110                 }
    111                 else
    112                 {
    113                     printf("send successfully!
    recv:%d Bytes,send:%d Bytes
    ",bufflen,len);
    114                 }
    115                 
    116             }
    117             
    118         } while(bufflen>0);
    119         closesocket(cli);
    120     }
    121     closesocket(server);
    122     WSACleanup();
    123     getchar();
    124     return 0;
    125 }

    客户端:

     1 #include <stdio.h>
     2 #include <winsock2.h>
     3 #pragma comment(lib,"ws2_32.lib")
     4 
     5 #define PORT 6666
     6 #define SERVERADDR "127.0.0.1"
     7 
     8 int main()
     9 {
    10     WSADATA wsaData = {};
    11     int err = WSAStartup(MAKEWORD(2,2),&wsaData);
    12     if(0 != err)
    13     {
    14         printf("failed with error:%d
    ", err);
    15         system("pause");
    16         return 1;
    17     }
    18     //创建套接字
    19     SOCKET client = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    20     if(INVALID_SOCKET == client)
    21     {
    22         printf("create socket failed with error:%d
    ",WSAGetLastError());
    23         WSACleanup();
    24         system("pause");
    25         return 1;
    26     }
    27     //准备服务器的信息
    28     SOCKADDR_IN server_addr = {};
    29     server_addr.sin_family = AF_INET;
    30     server_addr.sin_port = htons(PORT); //将本地字节序转换成网络字节序
    31     server_addr.sin_addr.S_un.S_addr = inet_addr(SERVERADDR);
    32     //开始连接服务器
    33     if(SOCKET_ERROR == connect(client,(SOCKADDR*)&server_addr,sizeof(server_addr)))
    34     {
    35         printf("connect to server with error:%d
    ",WSAGetLastError());
    36         closesocket(client);
    37         WSACleanup();
    38         system("pause");
    39         return 1;
    40     }
    41     int len = 0;
    42     char buff[MAXBYTE] = {0};
    43     char recv_buff[MAXBYTE];
    44     int flag=0;
    45     do
    46     {
    47         memset(buff,'',MAXBYTE);
    48         printf("请输入需要发送的内容:
    ");
    49         rewind(stdin);
    50         flag = scanf("%s",buff);
    51         if(EOF!= flag)
    52         {
    53             //printf("buff:%s,%d
    ",buff,strlen(buff));
    54             char t_buff[MAXBYTE] = "你好啊哈";
    55             int len = send(client,t_buff,strlen(t_buff),0);
    56             if(SOCKET_ERROR == len)
    57             {
    58                 printf("send failed with error:%d
    ",WSAGetLastError());
    59                 break;
    60             }
    61             //准备接收服务器的回声
    62             memset(recv_buff,0,sizeof(recv_buff));
    63             int recv_len = recv(client,recv_buff,sizeof(recv_buff),0);
    64             if(recv_len == 0)  //对方关闭连接了
    65             {
    66                 printf("service closed!
    ");
    67                 break;
    68             }
    69             else if (SOCKET_ERROR == recv_len)
    70             {
    71                 printf("recv failed with error:%d
    ",WSAGetLastError());
    72                 break;
    73             }
    74             //打印接收到的数据
    75             printf("received from server:%s
    ",recv_buff);
    76 
    77         }
    78     } while(flag!=EOF);
    79     closesocket(client);
    80     WSACleanup();
    81     system("pause");
    82     return 0;
    83 }

     

    总结:

    1. 服务器的程序在vscode上亲测没有问题,客户端程序通过查看代码可以看到,每次发的都是固定的字符串,原因是使用scanf函数获取字符串失败,目前没有找到原因,希望有人帮指点下。

    2. vscode的控制台使用的是utf-8字符编码格式,所以出现中文不会有乱码,如果是使用的是windows的控制台(ASCII编码格式)打开程序,出现中文会显示乱码,这是需要转码才能正常显示。

    参考:MultiByteToWideChar和WideCharToMultiByte函数,查询下MSDN。

     

    最后贴上一个用python写的简易客户端程序,我当时是用来快速检验服务端程序的,证明服务端程序能正常运行。

     1 from socket import socket
     2 s=socket()
     3 s.connect(('127.0.0.1',6666))
     4 while True:
     5     send_str = input("请输入需要发送的内容:
    ")
     6     if len(send_str)>0:
     7         s.send(send_str.encode())
     8     else:
     9         break
    10     res = s.recv(1024).decode()
    11     print(res)
    12     print('='*20)
    13 s.close()

    是不是感觉代码很简易,其实底层的实现都是一样的,python是做了一个封装,使用起来比较方便而已。

     

  • 相关阅读:
    Unit app.service is not loaded properly: Exec format error
    No journal files were found.
    下一代存储技术的先行: NVDIMM 你了解吗?
    How To Share Data Between the Docker Container and the Host
    perl: warning: Please check that your locale settings:
    淘宝推荐、视频搜索背后的检索技术竟是它!深度揭秘达摩院向量检索引擎Proxima
    这可能是大型复杂项目下数据流的最佳实践
    MaxCompute在电商场景中如何进行漏斗模型分析
    技术干货 | 阿里云数据库PostgreSQL 13大版本揭秘
    ACK正式支持对基于Alibaba Cloud Linux操作系统的集群进行等保加固
  • 原文地址:https://www.cnblogs.com/dz-study/p/13330612.html
Copyright © 2020-2023  润新知