代碼中使用到的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;
}