在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\n", 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\n");
 23         WSACleanup(); //释放系统资源
 24         system("pause");
 25         return 1;
 26     }
 27     else
 28     {
 29         printf("The WinSock 2.2 dll was found\n");
 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\n",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\n",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\n",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......\n");
 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\n",WSAGetLastError());
 76             closesocket(server);
 77             WSACleanup();
 78             system("pause");
 79             return 1;
 80         }
 81         //客户信息有效,打印下看看吧
 82         printf(">>client$\t%s:%d connected!\n",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!\n");
 95             }
 96             else if (SOCKET_ERROR == bufflen)
 97             {
 98                 printf("recv failed with error:%d\n",WSAGetLastError());
 99             }
100             else //接收到了数据
101             {
102                 buff[bufflen] = '\0';
103                 printf("received:%s\n",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\n",WSAGetLastError());
109                     break;
110                 }
111                 else
112                 {
113                     printf("send successfully!\nrecv:%d Bytes,send:%d Bytes\n",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\n", 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\n",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\n",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,'\0',MAXBYTE);
48         printf("请输入需要发送的内容:\n");
49         rewind(stdin);
50         flag = scanf("%s",buff);
51         if(EOF!= flag)
52         {
53             //printf("buff:%s,%d\n",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\n",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!\n");
67                 break;
68             }
69             else if (SOCKET_ERROR == recv_len)
70             {
71                 printf("recv failed with error:%d\n",WSAGetLastError());
72                 break;
73             }
74             //打印接收到的数据
75             printf("received from server:%s\n",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("请输入需要发送的内容:\n")
 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是做了一个封装,使用起来比较方便而已。

 

原文链接: https://www.cnblogs.com/dz-study/p/13330612.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

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

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/367879

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午6:05
下一篇 2023年3月2日 下午6:05

相关推荐