欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TCP实现网络通信(客户端和服务端)

程序员文章站 2022-07-01 15:02:20
...

内容简介

主要通过TCP实现客户端和服务端的通信,代码分为客户端和服务端,主要用于在客户端输入文件名获取服务端存在的文件,并下载到客户端。执行流程为:先启动服务端,然后在启动客户端,客户端输入需要访问的服务端文件名,服务端收到消息后,先查看是否文件存在,如果存在则将内容发送给客户端,如果不存在则给客户端发送文件不存在,请求客户端重新输入文件名。

代码

Server.h

#ifndef __TCP__
#define __TCP__
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<WinSock2.h>
#define BUFFER_SIZE 1024
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
//Windows相关环境初始化
int Init();
//创建服务端socket
void Create_Socket();
//绑定服务端socket
void Bind();
//通过服务端监听客户端
void Listen();
//接受客户端socket请求
void Accept();
//数据通讯
void Data_Communication();
#endif

Server.c

#include"Server.h"
SOCKADDR_IN server;
SOCKET server_socket;
SOCKADDR_IN clientMsg;
SOCKET client_socket;
int Init()
{
	int res;
	WORD wdVersion = MAKEWORD(2, 2);
	WSADATA wdSockMsg;
	res = WSAStartup(wdVersion, &wdSockMsg);
	if (0 != res)
	{
		switch (res)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库");
			break;
		case WSAEINPROGRESS:
			printf("请重新启动");
			break;
		case WSAEPROCLIM:
			printf("请尝试关掉不必要的软件,以为当前网络运行提供充足资源");
			break;
		}
		return -1;
	}
	//高位装的是副版本号,低位装的是主版本号
	if (2 != HIBYTE(wdSockMsg.wVersion) || 2 != LOBYTE(wdSockMsg.wVersion))
	{
		WSACleanup();
		return -2;
	}
	return res;
}
void Create_Socket()
{
	int Code;
	//这里如果使用sockaddr_in则需要加上struct
	//如果使用	SOCKADDR_IN则不需要
	server.sin_family = AF_INET;
	server.sin_port = htons(8087);
	server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == server_socket)
	{
		Code = WSAGetLastError();
		printf("Create_Socket Failed,Code = %d\n", Code);
		WSACleanup();
		return;
	}
}
void Bind()
{
	int Code;
	Code = bind(server_socket, (SOCKADDR*)&server, sizeof(SOCKADDR));
	if (SOCKET_ERROR == Code)
	{
		//如果想看错误码则需要在可能出错的语句后面执行WASGetLastError、
		Code = WSAGetLastError();
		//一定要先关闭socket连接,然后在清理网络库
		printf("Bind Failed,Code = %d\n", Code);
		closesocket(server_socket);
		WSACleanup();
		return;
	}
}
void Listen()
{
	//listen用于监听客户端传来的链接,accept将客户端的信息绑定到一个socket上,也就是
	//给客户端创建一个socket通道返回值返回给我们客户端的socket
	//一次只能创建一个,有几个客户端链接,就调用几次
	int Code;
	Code = listen(server_socket, SOMAXCONN);
	if (SOCKET_ERROR == Code)
	{
		Code = WSAGetLastError();
		printf("Listen Failed,Code = %d\n", Code);
		closesocket(server_socket);
		WSACleanup();
		return;
	}
}
void Accept()
{
	//创建客户端连接
	SOCKADDR_IN clientMsg;
	int len = sizeof(clientMsg);
	int Code;
	//下面语句为获取clientMsg里面的信息。如果不想获取则后两个则全为NULL
	//如何不想通过accept接收客户端信息,则可以这样写accept(socketserver,NULL,NULL)
	//getpeername(socketclient,(struct sockaddr*)&clientMsg,&len);
	//将客户端信息通过getpeername获取
	//getsockname用于获得本地的ip和端口
	//getsockname(socketclient,(struct sockaddr*)&sockclientMsg,&len);
	//无论第一个参数为socketclient
	//还是socketserver端口都为8087
	client_socket = accept(server_socket, (SOCKADDR*)&clientMsg, &len);
	if (INVALID_SOCKET == client_socket)
	{
		//如果想看错误码则需要在可能出错的语句后面执行WASGetLastError、
		Code = WSAGetLastError();
		//一定要先关闭socket连接,然后在清理网络库
		printf("Accept Failed,Code = %d\n", Code);
		closesocket(client_socket);
		closesocket(server_socket);
		WSACleanup();
		return;
	}
	printf("\t客户端连接成功!!!\n");
}
void Data_Communication()
{
	int Code;
	char buf[BUFFER_SIZE];
	FILE* fp;
	//注意不用考虑\0;
	if (SOCKET_ERROR == send(client_socket, "我是服务端,我收到了你的消息!!!\n", strlen("我是服务端,我收到了你的消息!!!\n"), 0))
	{
		Code = WSAGetLastError();
		printf("Send Failed,Code = %d\n", Code);
		closesocket(client_socket);
		closesocket(server_socket);
		return;
	}
	while (1)
	{
		memset(buf, 0, sizeof(buf));
		Code = recv(client_socket, buf, BUFFER_SIZE, 0);
		if (0 == Code)
		{
			printf("客户端下线=%d\n",Code);
			return;
		}
		else if (SOCKET_ERROR == Code)
		{
			Code = WSAGetLastError();
			printf("Recv Failed,Code=%d",Code);
			closesocket(client_socket);
			closesocket(server_socket);
			WSACleanup();
			return;
		}
		else
		{
			printf("%d\t%s\n", Code, buf);
		}
		fp = fopen(buf, "rb+");
		if (fp == NULL)
		{
			memset(buf, 0, sizeof(buf));
			sprintf(buf, "%s","The file doesn't exist!!\n");
			if (SOCKET_ERROR == send(client_socket, buf, strlen(buf), 0))
			{
				Code = WSAGetLastError();
				printf("Send check file formation failed,Code = %d", Code);
				closesocket(client_socket);
				closesocket(server_socket);
				WSACleanup();
				return;
			}
			continue;
		}
		memset(buf, 0, sizeof(buf));
		while (fgets(buf, sizeof(buf), fp) != NULL)
		{
			if (SOCKET_ERROR == send(client_socket, buf, strlen(buf), 0))
			{
				Code = WSAGetLastError();
				printf("Send file content failed,Code= %d", Code);
				closesocket(client_socket);
				closesocket(server_socket);
				WSACleanup();
				return;
			}
			memset(buf, 0, sizeof(buf));
		}
		fclose(fp);
	}
	closesocket(client_socket);
	closesocket(server_socket);
	WSACleanup();
	system("pause");
}

main.c(测试程序)

#include "Server.h"
int main()
{
	int Code;
	Code = Init();
	printf("Init_Code = %d\n", Code);
	Create_Socket();
	Bind();
	Listen();
	Accept();
	Data_Communication();
	return 0;
}

Client.h

#ifndef __TCP__
#define __TCP__
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#include<WinSock2.h>
#define  PORT 8087
#define SERVER_IP  "127.0.0.1"
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
#pragma warning(disable:4996)
#pragma comment(lib,"WS2_32")
//Windows相关环境初始化
int Init();
//创建客户端socket
void Create_Socket();
//接受客户端socket请求
void Connect();
//数据通讯
void Data_Communication();
#endif

Client.c

#include "Client.h"
SOCKET client_socket;
int Init()
{
	int res;
	WORD wdVersion = MAKEWORD(2, 2);
	WSADATA wdSockMsg;
	res = WSAStartup(wdVersion, &wdSockMsg);
	if (0 != res)
	{
		switch (res)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库");
			break;
		case WSAEINPROGRESS:
			printf("请重新启动");
			break;
		case WSAEPROCLIM:
			printf("请尝试关掉不必要的软件,以为当前网络运行提供充足资源");
			break;
		}
		return -1;
	}
	//高位装的是副版本号,低位装的是主版本号
	if (2 != HIBYTE(wdSockMsg.wVersion) || 2 != LOBYTE(wdSockMsg.wVersion))
	{
		WSACleanup();
		return -2;
	}
	return res;
}
void Create_Socket()
{
	client_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (SOCKET_ERROR == client_socket)
	{
		printf("Create Socket Error!");
		return;
	}
}
void Connect()
{
	//指定服务端的地址
	SOCKADDR_IN server_addr;
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);
	server_addr.sin_port = htons(PORT);
	if (SOCKET_ERROR == connect(client_socket, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)))
	{
		printf("Can Not Connect To Server IP!\n");
		return;
	}
}
void Data_Communication()
{
	char file_name[FILE_NAME_MAX_SIZE];
	size_t length = 0;
	char buffer[BUFFER_SIZE];
	FILE* fp;
	//输入文件名
	memset(buffer, 0, sizeof(buffer));
	if ((length = recv(client_socket, buffer, BUFFER_SIZE, 0))>0)
	{
		printf("%s", buffer);
		memset(buffer, 0, sizeof(buffer));
	}
	while (TRUE)
	{
		memset(file_name, 0, sizeof(file_name));
		printf("Please Input File Name On Server: ");
		scanf("%s", file_name);
		memset(buffer, 0, sizeof(buffer));
		if (send(client_socket, file_name, strlen(file_name), 0) < 0)
		{
			printf("Send File Name Failed\n");
			return;
		}
		memset(buffer, 0, sizeof(buffer));
		if ((length = recv(client_socket, buffer, BUFFER_SIZE, 0))>0)
		{
			if (strncmp(buffer, "The file doesn't", strlen("The file doesn't")) == 0)
			{
				printf("%s", buffer);
				memset(buffer, 0, sizeof(buffer));
				continue;
			}
			else
			{
				fp = fopen(file_name, "wb+");
				if (NULL == fp)
				{
					printf("File:%s Can Not Open To Write\n", file_name);
					return ;
				}
				else
				{
					if (fwrite(buffer, 1, length, fp) < length)
					{
						printf("File:%s Write Failed\n", file_name);
						break;
					}
					printf("%s", buffer);
					memset(buffer, 0, sizeof(buffer));
					//文件中的内容可以通过一个recv去接收
					length = recv(client_socket, buffer, BUFFER_SIZE, 0);
					if (fwrite(buffer, 1, length, fp) < length)
					{
						printf("File:%s Write Failed\n", file_name);
						break;
					}
					printf("%s", buffer);
					memset(buffer, 0, sizeof(buffer));
					printf("Receive File:%s From Server Successful!\n", file_name);
					fclose(fp);
				}
			}
		}
	}
	closesocket(client_socket);
	WSACleanup();
}

main.c(测试程序)

#include "Client.h"
int main(int argc, const char* argv[])
{
	int Code;
	Code = Init();
	printf("Init_Code = %d\n", Code);
	Create_Socket();
	Connect();
	Data_Communication();
	return 0;
}

运行结果:

成功读取文件内容
TCP实现网络通信(客户端和服务端)
在客户端下载了服务端的文件
TCP实现网络通信(客户端和服务端)
客户端输入的文件名在服务端无法找到
TCP实现网络通信(客户端和服务端)

相关标签: TCP 网络通信