代码中使用到的API参见官网:https://docs.microsoft.com/zh-cn/windows/desktop/api/winsock2/
UDP套接字关键步骤:
服务端 | 客户端 |
初始化WSA、创建socket | 初始化WSA、创建socket |
创建地址结构:sockaddr_in | 创建地址结构:sockaddr_in |
绑定socket和地址结构:bind() |
|
接收消息: recvfrom() | 发送消息:sendto() |
关闭Socket、注销WSA | 关闭Socket、注销WSA |
UDP服务端代码如下:
//Socket服务器端代码
#include <tchar.h>
#include <stdio.h>
#include <winsock2.h>
#include <stdlib.h>
#include <string.h>
#include <Ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#define BUFFER_SIZE 2048
int main(int argc, char* argv[]){
//初始化WSA,使得程序可以调用windows socket,WSA版本指定为2.2
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0){
return 0;
}
//创建套接字,server_socket,类型是UDP
SOCKET server_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (server_socket == INVALID_SOCKET) {
//如果创建的socket无效,则结束程序
perror("socket error !\n");
return 0;
}
//创建地址结构,server_addr,并设置端口和IP
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
//端口号 8887
server_addr.sin_port = htons(8887);
//此处INADDR_ANY表示所有本机IP地址
server_addr.sin_addr.S_un.S_addr = INADDR_ANY;
//将socket与地址server_addr绑定
if (bind(server_socket, (LPSOCKADDR)&server_addr, sizeof(server_addr)) == SOCKET_ERROR){
perror("bind error !\n");
return 0;
}
//循环接收来自客户端的消息
while (1){
// 定义客户端的socket地址结构
sockaddr_in client_addr;
int client_addr_length = sizeof(client_addr);
// recv函数接收数据到缓冲区buffer中
char buffer[BUFFER_SIZE];
memset(buffer, 0, BUFFER_SIZE);
if (recvfrom(server_socket, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&client_addr, &client_addr_length) == -1){
perror("接收消息失败:\n");
break;
}
//将收到的消息输出到命令行
char IP_BUFFER[256];
memset(IP_BUFFER, 0, 256);
InetNtop(AF_INET, &client_addr.sin_addr, IP_BUFFER, 256);
printf("从%s:%d处收到消息:%s\n", IP_BUFFER, ntohs(client_addr.sin_port), buffer);
}
// 关闭服务器socket 并注销 WSA
closesocket(server_socket);
WSACleanup();
system("pause");
return 0;
}
UDP客户端代码如下:
//Socket客户端代码
//向服务器发送消息
#include <tchar.h>
#include <stdio.h>
#include <winsock2.h>
#include <stdlib.h>
#include <string.h>
#include <Ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#define BUFFER_SIZE 2048
int main(int argc, char* argv[]){
//初始化WSA,使得程序可以调用windows socket
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0) {
return 0;
}
//创建客户端套接字,client_socket,类型是UDP
SOCKET client_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (client_socket == INVALID_SOCKET) {
//如果创建的socket无效,则结束程序
perror("socket error !\n");
return 0;
}
//创建地址,server_addr,并设置端口和IP
sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
//要连接的服务器端口号 8887
server_addr.sin_port = htons(8887);
//绑定服务器的地址127.0.0.1
InetPton(AF_INET, "127.0.0.1", &server_addr.sin_addr.s_addr);
printf("请输入发送给服务器的消息:\n");
while (1){
char buffer[BUFFER_SIZE];
memset(buffer, 0, BUFFER_SIZE);
// 从键盘中读取输入到BUFFER中
gets_s(buffer, BUFFER_SIZE);
//发送数据给服务器
if (sendto(client_socket, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&server_addr, sizeof(SOCKADDR)) == -1){
perror("发送消息失败:\n");
break;
}
}
// 关闭服务器socket 并注销 WSA
closesocket(client_socket);
WSACleanup();
system("pause");
return 0;
}
TCP套接字关键步骤:
服务端 | 客户端 |
1.初始化WSA、创建socket | 1.初始化WSA、创建socket |
2.创建地址结构:sockaddr_in | 2.创建地址结构:sockaddr_in |
3.绑定socket和地址结构:bind() | 3.请求连接:connect() |
4.监听 listen() | 4.发送/接收消息:send()/rece() |
5.通信过程: a)接收连接请求 accept() b)发送/接收消息 rece()/send() c)关闭连接 closesocket() | 5.关闭Socket、注销WSA |
6.关闭Socket、注销WSA |
|
TCP服务端代码如下:
//Socket服务器端代码
#include <tchar.h>
#include <stdio.h>
#include <winsock2.h>
#include <stdlib.h>
#include <string.h>
#include <Ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#define BUFFER_SIZE 2048
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char* argv[]){
//初始化WSA,使得程序可以调用windows socket
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0){
return 0;
}
//创建监听用套接字,server_socket,类型是TCP
SOCKET server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket == INVALID_SOCKET) {
perror("socket error !\n");
return 0;
}
//创建地址,server_addr,并设置端口和IP
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
//端口号 8888
server_addr.sin_port = htons(8888);
//INADDR_ANY表示本机任意IP地址
server_addr.sin_addr.S_un.S_addr = INADDR_ANY;
//将socket与地址server_addr绑定
if (bind(server_socket, (LPSOCKADDR)&server_addr, sizeof(server_addr)) == SOCKET_ERROR){
perror("bind error !\n");
return 0;
}
//server_socket开始监听
if (listen(server_socket, 20) == SOCKET_ERROR){
perror("listen error !\n");
return 0;
}
while (1){
printf("等待连接...\n");
// 定义客户端的socket和socket地址结构
SOCKET client_socket;
sockaddr_in client_addr;
int client_addr_length = sizeof(client_addr);
// 接受连接请求,返回一个新的socket(描述符),这个新socket用于同连接的客户端通信
// accept函数会把连接到的客户端信息写到client_addr中
client_socket = accept(server_socket, (SOCKADDR *)&client_addr, &client_addr_length);
if (client_socket == INVALID_SOCKET){
perror("Socket连接建立失败:\n");
continue;
}
char IP_BUFFER[256];
memset(IP_BUFFER, 0, 256);
InetNtop(AF_INET, &client_addr.sin_addr, IP_BUFFER,256);
printf("Socket连接建立,客户端IP为:%s,端口为:%d\n", IP_BUFFER, ntohs(client_addr.sin_port));
//接收客户端请求的的文件路径
// recv函数接收数据到缓冲区buffer中
char buffer[BUFFER_SIZE];
memset(buffer,0, BUFFER_SIZE);
if (recv(client_socket, buffer, BUFFER_SIZE, 0) < 0){
perror("接收文件名失败:\n");
break;
}
// 然后从buffer拷贝到file_name中
char file_name[FILE_NAME_MAX_SIZE + 1];
memset(file_name, 0,FILE_NAME_MAX_SIZE + 1);
strncpy_s(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE ? FILE_NAME_MAX_SIZE : strlen(buffer));
// 打开文件并读取文件数据
FILE *fp;
errno_t F_ERR= fopen_s(&fp,file_name, "rb");
if (F_ERR != 0){
printf("文件打开失败:%s\n", file_name);
}
else{
printf("开始传输文件:%s\n", file_name);
memset(buffer,0, BUFFER_SIZE);
int length = 0;
// 每读取一段数据,便将其发送给客户端,循环直到文件读完为止
while ((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0){
if (send(client_socket, buffer, length, 0) < 0){
printf("文件发送失败:%s/n", file_name);
break;
}
memset(buffer,0, BUFFER_SIZE);
}
// 关闭文件
fclose(fp);
printf("文件传输完成:%s!\n", file_name);
}
// 关闭与客户端的连接
closesocket(client_socket);
}
// 关闭监听用的socket
closesocket(server_socket);
WSACleanup();
return 0;
}
TCP客户端代码如下:
//Socket客户端代码
#include <tchar.h>
#include <stdio.h>
#include <winsock2.h>
#include <stdlib.h>
#include <string.h>
#include <Ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#define BUFFER_SIZE 2048
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char* argv[]){
//初始化WSA,使得程序可以调用windows socket
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0){
return 0;
}
//创建监听用套接字,server_socket
SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ;
if (client_socket == INVALID_SOCKET) {
perror("socket error !");
return 0;
}
//创建地址结构,server_addr,并设置端口和IP
sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
//要连接的服务器端口号 8888
server_addr.sin_port = htons(8888);
//指定服务器的地址127.0.0.1
InetPton(AF_INET, "127.0.0.1",&server_addr.sin_addr.s_addr);
//与地址server_addr建立连接
if (connect(client_socket, (SOCKADDR*)&server_addr, sizeof(SOCKADDR))){
perror("connect error !\n");
return 0;
}
char remote_file_name[FILE_NAME_MAX_SIZE + 1];
memset(remote_file_name, 0, FILE_NAME_MAX_SIZE + 1);
printf("请输入要获取的服务器文件路径:\n");
scanf_s("%s", remote_file_name, FILE_NAME_MAX_SIZE);
char local_file_name[FILE_NAME_MAX_SIZE + 1];
memset(local_file_name, 0, FILE_NAME_MAX_SIZE + 1);
printf("请输入保存文件的本地路径:\n");
scanf_s("%s", local_file_name, FILE_NAME_MAX_SIZE);
char buffer[BUFFER_SIZE];
memset(buffer,0 , BUFFER_SIZE);
strncpy_s(buffer, remote_file_name, strlen(remote_file_name)>BUFFER_SIZE ? BUFFER_SIZE : strlen(remote_file_name));
// 向服务器发送buffer中的数据
if (send(client_socket, buffer, BUFFER_SIZE, 0) < 0){
perror("发送文件名失败:");
exit(1);
}
// 打开文件,准备写入
FILE *fp;
errno_t F_ERR = fopen_s(&fp, local_file_name, "wb");
if (F_ERR != 0){
printf("文件打开失败:%s\n", local_file_name);
exit(1);
}
// 从服务器接收数据到buffer中
// 每接收一段数据,便将其写入文件中,循环直到文件接收完并写完为止
memset(buffer,0, BUFFER_SIZE);
int length = 0;
while ((length = recv(client_socket, buffer, BUFFER_SIZE, 0)) > 0){
if (fwrite(buffer, sizeof(char), length, fp) < length){
printf("文件写入失败:%s\n", local_file_name);
break;
}
memset(buffer, 0, BUFFER_SIZE);
}
printf("\n成功从服务器接收文件\n存入本地目录:%s\n", remote_file_name, local_file_name);
// 接收成功后,关闭文件,关闭socket、WSA
fclose(fp);
closesocket(client_socket);
WSACleanup();
system("pause");
return 0;
}