Linux网络编程——基于tcp/ip的模拟聊天(文件传输)工具

在Linux环境下,使用TCP/IP协议,通过C语言开发了一个网络通信系统,支持多用户聊天和文件共享。用户可以发送ls命令查看服务器文件目录,使用get和put命令进行文件的上传与下载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开发平台:Linux
开发工具:Ubuntu, sourceInsight4.0
项目介绍: 本项目基于TCP/IP协议创建一个网络通信系统,可以实现客户之间的聊天通信以及文件传输,同时利用进程实现多客户群聊,多个客户也可同时从服务器下载文件实现文件共享,客户可向服务器发送ls命令获取服务器端的文件目录,并发送get+filename获取文件,也可发送put+filename上传文件到服务器。
protocol.h

#ifndef __PROTOCOL_H__
#define __PROTOCOL_H__

#define FTP_ROOT_DIR   "/home/gec/tftp"


//命令号, 命令参数


//命令号->  整数
enum CMD_NO 
{
	FTP_CMD_LS = 1024, //
	FTP_CMD_GET,
	FTP_CMD_PUT,
	FTP_CMD_BYE,
	
	FTP_CMD_NUM // 命令个数
};

//出错码
enum resp_result
{
	RESP_SUCCESS = 0, //成功
	RESP_PACK_ERROR, //失败,包的长度不对
	RESP_PACK_NOEND, //包没有结束,可以再次收包
	RESP_PACK_NOFILE //没有可以获取的文件
};


//参数: 参数长度, 参数内容



/*
	0xc0 : 包头

	pkg_len ;//4bytes, 小端模式,整个数据包的长度
				 4(pkg_len) + 4 (cmd_no) + arg_1 +...
	cmd_no // 4bytes, 小端模式

	arg_1;
		arg_1_len; //4bytes , 小端模式
		arg_1_data; len长度
	arg_2:
		arg_2_len; //4bytes,小端模式
		arg_2_data;
	....

	0xC0:包尾
*/

// cmd: ls

//0xc0  ___包长度______    __命令号()__             0xc0
// 0xc0  0x80 0x00 0x00 0x00 


//cmd: get
//0xc0 ____包长度(4)___ ___命令号(4)___   ___arg_1_Len(4)_   ___filename(r)___ 0xc0




#if 0
unsigned char cmd[1024];
int i = 0;

int pkg_len = 1024;

cmd[0] = 0xc0;

cmd[1] = pkg_len & 0xff;
cmd[2] = ( pkg_len >> 8) & 0xff;
cmd[3] = (pkg_len >> 16) & 0xff;
cmd[4] = (pkg_len >> 24) & 0xff;
#endif



//CMD_RESP
/*
	0xc0: 包头

	pkg_len: 整个数据包的长度,4bytes, 小端模式
	cmd_no :  命令号,4bytes, 小端模式,表示回复哪条命令
	resp_len: 回复内容的长度,4bytes, 小端模式
			result  + resp_conent
			1 + x
	result:  执行成功或失败,1 bytes , 0表示成功,其他表示失败
	resp_conent: 回复内容
			成功:
				ls: 文件名字  各文件名之间用空格分隔
				get: 文件大小,4bytes, 小端模式

			失败:
				 出错码

	0xc0:包尾
*/


//ls 的回复
// 0xc0  --pkg_Len(4)---   ---cmd_No(4)---  --resp_len(4)--  --result(1)--  --filenames(r, 名字以空格分开)--- 0xc0


//get 的回复
//0xc0  ---pkg_len(4)---  ----cmd_no(4)---  ---resp_len(4)---   ---result(1)--  --file_size(4, 小端模式)--  0xc0

#endif

tcp_client.c

#include <sys/types.h>          /* See NOTES */	
#include <sys/stat.h>
#include <fcntl.h>	   
#include <sys/socket.h>	   
#include <netinet/in.h>			   
#include <arpa/inet.h>
#include <linux/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "protocol.h"


int connect_server(char *ip,int port)
{
/**1.创建套接字**/
	int sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == sockfd)
	{
		perror("socket error");
		return -1;
	}
	
/**2.发起链接请求**/
	int ret;
	struct sockaddr_in sAddr;
	memset(&sAddr,0,sizeof(sAddr));
	sAddr.sin_family = AF_INET;
	sAddr.sin_port = htons(port);
	sAddr.sin_addr.s_addr = inet_addr(ip);
	ret = connect(sockfd,(struct sockaddr*)&sAddr,sizeof(sAddr));
	if(-1 ==ret)
	{
		perror("conncet error");
		return -1;
	}
	//
	return sockfd;
}

void send_cmd(int sockfd,unsigned char *cmd,int len)
{
	//
	int ret = send(sockfd,cmd,len,0);
	if(-1 == ret)
	{
		perror("send cmd error");
		return;
	}
	//
}

void recv_ls_val(int sockfd)
{
	/**
		服务器回复数据,事先会回复一个数据包
			0xc0  		 	L E N S   			 E R R N 			  S I Z E 			 0xc0 
						回复数据包长度		回复的验证信息			后续正文大小
		紧接着服务器会回复正文
			size个字节的数据
	**/
	
	int i=0;
	unsigned char ch = 0;
	unsigned char cmd[500] = {0};
/*************************************接收回复数据包*******************************************************/	
	//命令以0xc0开头,所以如果收到的不是0xc0则舍弃不要
	do
	{
		//
		read(sockfd,&ch,1);
		perror("read ls");
	}while(ch != 0xc0);
	//
	//排除连续的0xc0
	while(ch == 0xc0)
	{
		read(sockfd,&ch,1);
	}//确保读取的是数据包的第一个字节
	//
	while(ch != 0xc0)//读到的是数据包的内容,读到包尾结束
	{
		cmd[i++] = ch;
		read(sockfd,&ch,1);
	}
/***************************************数据包接收完成*****************************************************/	
	
	
/******************************************解析数据包******************************************************/	
	//解析包长
	int cmd_len = cmd[0] | cmd[1]<<8 | cmd[2]<<16 | cmd[3]<<24;
	if(cmd_len != i)
	{
		printf("read value error,the pack len is no right\n");
		//send_error(connfd);
		return;
	}
	
	//解析验证信息
	int err_no = cmd[4] | cmd[5]<<8 | cmd[6]<<16 | cmd[7]<<24;
	if(err_no == RESP_PACK_ERROR)
	{
		printf("cmd error\n");
		return;
	}
	
	int data_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24;
	printf("recv data len:%d\n",data_len);
/*****************************************解析完毕**********************************************************/	



/****************************************接收回复正文*******************
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值