套接字编程入门

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/i_chaoren/article/details/81280480

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

猜你喜欢

转载自blog.csdn.net/i_chaoren/article/details/81280480