目录
- 编译环境
- 快速入门
- 编译指令
- 服务端code
- 客户端code
- 参考文章以及遇到的问题
编译环境
我的demo是通过此文章从C++更改成的C,编译环境使用的是Mingw,如下图所示
快速入门
- 拷贝代码
- 编译
- 互传消息
编译指令
- 客户端:gcc .\udpclient.c -lwsock32 -o udpclient.exe
- 服务端:gcc .\udpserver.c -lwsock32 -o udpserver.exe
运行两个可执行程序
客户端给目标地址(127.0.0.1(本机地址)),端口为4567发送数据数据nihao
本机服务端接收到客户端发送的数据,准备给客户端返回数据nihaoya
这时候已经代表了一次通讯的结束,代码中还有对bye的判断,其实是多余的,如下图所示,这时候服务端接收到了bye,退出了程序,但是客户端没退出,需要强制退出,所以我认为这个bye是多余的。
服务端code
udpserver.c
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 1024
#define SERVER_FAMILY AF_INET
#define SERVER_PORT 4567
#define SERVER_ADDR INADDR_ANY
void config_server(SOCKADDR_IN *addr_server)
{
addr_server->sin_family = SERVER_FAMILY;
addr_server->sin_port = htons(SERVER_PORT);
addr_server->sin_addr.S_un.S_addr = SERVER_ADDR;
}
int main()
{
WSADATA WSAData;
char receBuf[BUFFER_SIZE];
char Response[BUFFER_SIZE];
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
{
printf("init error\n");
exit(1);
}
SOCKET sockServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockServer == INVALID_SOCKET)
{
printf("Failed socket() \n");
return 0;
}
SOCKADDR_IN addr_Server; // 服务器的地址等信息
config_server(&addr_Server);
if (bind(sockServer, (SOCKADDR *)&addr_Server, sizeof(addr_Server)) == SOCKET_ERROR)
{ // 服务器与本地地址绑定
printf("Failed socket() %d \n", WSAGetLastError());
return 0;
}
SOCKADDR_IN addr_Clt;
int fromlen = sizeof(addr_Clt);
while (true)
{
int last = recvfrom(sockServer, receBuf, sizeof(receBuf), 0, (SOCKADDR *)&addr_Clt, &fromlen);
printf("last:%d\n", last);
if (last > 0)
{ // 判断接收到的数据是否为空
receBuf[last] = '\0'; // 给字符数组加一个'\0',表示结束了。不然输出有乱码
if (strcmp(receBuf, "bye") == 0)
{
printf("client disconnect...\n");
closesocket(sockServer);
return 0;
}
else
{
printf("receive data(%s):%s\n", inet_ntoa(addr_Clt.sin_addr), receBuf);
}
}
printf("please input send data:");
scanf("%s", Response);
printf("Response:%s,len:%d\n", Response, strlen(Response));
int r_sento = sendto(sockServer, Response, strlen(Response), 0, (SOCKADDR *)&addr_Clt, sizeof(SOCKADDR));
printf("return :%d\n", r_sento);
}
closesocket(sockServer);
WSACleanup();
return 0;
}
客户端code
udpclient.c
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 1024 // 缓冲区大小
#define SERVER_FAMILY AF_INET
#define SERVER_PORT 4567
#define SERVER_ADDR "127.0.0.1"
static char s_receBuf[BUFFER_SIZE]; // 发送数据的缓冲区
static char s_sendBuf[BUFFER_SIZE]; // 接受数据的缓冲区
void config_server(SOCKADDR_IN *addr_server)
{
addr_server->sin_family = SERVER_FAMILY;
addr_server->sin_port = htons(SERVER_PORT);
addr_server->sin_addr.S_un.S_addr = inet_addr(SERVER_ADDR);
}
int main()
{
SOCKET sock_Client; // 客户端用于通信的Socket
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
{
printf("init error");
return -1;
} // 初始化
sock_Client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // 创建客户端用于通信的Socket
SOCKADDR_IN addr_server; // 服务器的地址数据结构
config_server(&addr_server);
SOCKADDR_IN sock;
int len = sizeof(sock);
while (true)
{
printf("please input send data:");
scanf("%s", s_sendBuf);
sendto(sock_Client, s_sendBuf, strlen(s_sendBuf), 0, (SOCKADDR *)&addr_server, sizeof(SOCKADDR));
// int last = recv(sock_Client, s_receBuf, strlen(s_receBuf), 0); // (调用recv和recvfrom都可以)
int last = recvfrom(sock_Client, s_receBuf, sizeof(s_receBuf), 0, (SOCKADDR *)&sock, &len);
printf("last:%d,%s\n", last, s_receBuf);
if (last > 0)
{
s_receBuf[last] = '\0'; // 给字符数组加一个'\0',表示结束了。不然输出有乱码
if (strcmp(s_receBuf, "bye") == 0)
{
printf("server disconnect\n");
break;
}
else
{
printf("receive data:%s\n", s_receBuf);
}
}
}
closesocket(sock_Client);
WSACleanup();
return 0;
}
参考文章以及遇到的问题
参考文章:
C语言实现Windows下获取IP和MAC地址
Windows网络编程之UDP通信
其中Windows网络编程之UDP通信文章中客户端以及服务端都有bug,会造成通信失败,或者程序崩溃的情况。
服务端bug如下图所示
客户端bug如下图所示