1. 基于TCP的本地客户端、服务端信息交互实例(windows)(已验证)
实现功能:
本地TCP客户端往本地TCP服务端发送数据,TCP服务端收到数据则会打印输出,同时把原数据返回给TCP客户端。这个例子类似于我们在做单片机的串口实验时,串口上位机往我们的单片机发送数据,单片机收到数据则把该数据原样返回给上位机。
(1)服务端程序tcp_server.c
#include <stdio.h>
#include <winsock2.h>
#define BUF_LEN 100
int main(void)
{
WSADATA wd;
SOCKET ServerSock, ClientSock;
char Buf[BUF_LEN] = {0};
SOCKADDR ClientAddr;
SOCKADDR_IN ServerSockAddr;
int addr_size = 0, recv_len = 0;
/* 初始化操作sock需要的DLL */
WSAStartup(MAKEWORD(2,2),&wd);
/* 创建服务端socket */
if (-1 == (ServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
{
printf("socket error!\n");
exit(1);
}
/* 设置服务端信息 */
memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); // 给结构体ServerSockAddr清零
ServerSockAddr.sin_family = AF_INET; // 使用IPv4地址
ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 本机IP地址
ServerSockAddr.sin_port = htons(1314); // 端口
/* 绑定套接字 */
if (-1 == bind(ServerSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR)))
{
printf("bind error!\n");
exit(1);
}
/* 进入监听状态 */
if (-1 == listen(ServerSock, 10))
{
printf("listen error!\n");
exit(1);
}
addr_size = sizeof(SOCKADDR);
while (1)
{
/* 监听客户端请求,accept函数返回一个新的套接字,发送和接收都是用这个套接字 */
if (-1 == (ClientSock = accept(ServerSock, (SOCKADDR*)&ClientAddr, &addr_size)))
{
printf("socket error!\n");
exit(1);
}
/* 接受客户端的返回数据 */
int recv_len = recv(ClientSock, Buf, BUF_LEN, 0);
printf("客户端发送过来的数据为:%s\n", Buf);
/* 发送数据到客户端 */
send(ClientSock, Buf, recv_len, 0);
/* 关闭客户端套接字 */
closesocket(ClientSock);
/* 清空缓冲区 */
memset(Buf, 0, BUF_LEN);
}
/*如果有退出循环的条件,这里还需要清除对socket库的使用*/
/* 关闭服务端套接字 */
//closesocket(ServerSock);
/* WSACleanup();*/
return 0;
}
---------------------------------分割线---------------------------------
(2)客户端程序tcp_client.c
#include <stdio.h>
#include <winsock2.h>
#define BUF_LEN 100
int main(void)
{
WSADATA wd;
SOCKET ClientSock;
char Buf[BUF_LEN] = {0};
SOCKADDR_IN ServerSockAddr;
/* 初始化操作sock需要的DLL */
WSAStartup(MAKEWORD(2,2),&wd);
/* 向服务器发起请求 */
memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));
ServerSockAddr.sin_family = AF_INET;
ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ServerSockAddr.sin_port = htons(1314);
while (1)
{
/* 创建客户端socket */
if (-1 == (ClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
{
printf("socket error!\n");
exit(1);
}
if (-1 == connect(ClientSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR)))
{
printf("connect error!\n");
exit(1);
}
printf("请输入一个字符串,发送给服务端:");
gets(Buf);
/* 发送数据到服务端 */
send(ClientSock, Buf, strlen(Buf), 0);
/* 接受服务端的返回数据 */
recv(ClientSock, Buf, BUF_LEN, 0);
printf("服务端发送过来的数据为:%s\n", Buf);
memset(Buf, 0, BUF_LEN); // 重置缓冲区
closesocket(ClientSock); // 关闭套接字
}
// WSACleanup(); /*如果有退出循环的条件,这里还需要清除对socket库的使用*/
return 0;
}
---------------------------------分割线---------------------------------
(3.1) 方法一:在 EditPlus下编译,步骤如下:
在编译器中,加参数 -lwsock32,即可!
成功编译,生成 exe
---------------------------------分割线---------------------------------
(3.2) 方法二:在 DOS 下编译,步骤如下:
a)win+R进入dos
b)输入d:
c)输入路径 cd D:\Cplusplus\udpTest(我的文件路径)
d)先输入gcc tcp_client.c -o tcp_client.exe -lwsock32
e)再输入gcc tcp_server.c -o tcp_server.exe -lwsock32
成功生成 exe文件!
---------------------------------分割线---------------------------------
(5)实验步骤:
先启动服务端程序tcp_server.exe,再启动客户端程序tcp_client.exe,并在客户端中输入字符串,则当服务端会接收到字符串时会打印输出,与此同时也会往客户端返回相同的数据。
运行结果:
---------------------------------分割线---------------------------------
2. 基于UDP的本地客户端、服务端信息交互实例(待验证zhy20210913)
(1)server 程序 udp_server.c
#include <stdio.h>
#include <winsock2.h>
#define BUF_LEN 100
int main(void)
{
WSADATA wd;
SOCKET ServerSock;
char Buf[BUF_LEN] = {0};
SOCKADDR ClientAddr;
SOCKADDR_IN ServerSockAddr;
int addr_size = 0;
/* 初始化操作sock需要的DLL */
WSAStartup(MAKEWORD(2,2),&wd);
/* 创建服务端socket */
if(-1 == (ServerSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)))
{
printf("socket error!\n");
exit(1);
}
/* 设置服务端信息 */
memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); // 给结构体ServerSockAddr清零
ServerSockAddr.sin_family = AF_INET; // 使用IPv4地址
ServerSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 自动获取IP地址
ServerSockAddr.sin_port = htons(1314); // 端口
/* 绑定套接字 */
if (-1 == (bind(ServerSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR))))
{
printf("bind error!\n");
exit(1);
}
addr_size = sizeof(SOCKADDR);
while (1)
{
/* 接受客户端的返回数据 */
int str_len = recvfrom(ServerSock, Buf, BUF_LEN, 0, &ClientAddr, &addr_size);
printf("客户端发送过来的数据为:%s\n", Buf);
/* 发送数据到客户端 */
sendto(ServerSock, Buf, str_len, 0, &ClientAddr, addr_size);
/* 清空缓冲区 */
memset(Buf, 0, BUF_LEN);
}
/*如果有退出循环的条件,这里还需要清除对socket库的使用*/
/* 关闭服务端套接字 */
//closesocket(ServerSock);
/* WSACleanup();*/
return 0;
}
---------------------------------分割线---------------------------------
(2)client 程序 udp_client.c
#include <stdio.h>
#include <winsock2.h>
#define BUF_LEN 100
int main(void)
{
WSADATA wd;
SOCKET ClientSock;
char Buf[BUF_LEN] = {0};
SOCKADDR ServerAddr;
SOCKADDR_IN ServerSockAddr;
int ServerAddrLen = 0;
/* 初始化操作sock需要的DLL */
WSAStartup(MAKEWORD(2,2),&wd);
/* 创建客户端socket */
if (-1 == (ClientSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)))
{
printf("socket error!\n");
exit(1);
}
/* 向服务器发起请求 */
memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));
ServerSockAddr.sin_family = PF_INET;
ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ServerSockAddr.sin_port = htons(1314);
ServerAddrLen = sizeof(ServerAddr);
while (1)
{
printf("请输入一个字符串,发送给服务端:");
gets(Buf);
/* 发送数据到服务端 */
sendto(ClientSock, Buf, strlen(Buf), 0, (struct sockaddr*)&ServerSockAddr, sizeof(ServerSockAddr));
/* 接受服务端的返回数据 */
recvfrom(ClientSock, Buf, BUF_LEN, 0, &ServerAddr, &ServerAddrLen);
printf("服务端发送过来的数据为:%s\n", Buf);
memset(Buf, 0, BUF_LEN); // 重置缓冲区
}
closesocket(ClientSock); // 关闭套接字
// WSACleanup(); /*如果有退出循环的条件,这里还需要清除对socket库的使用*/
return 0;
}