022——设计通信帧格式

本期没想好怎么排版以流水账形式展示了

int tcp_server(int argc, char *argv[]) 
{
    int server_fd, client_fd;  
    struct sockaddr_in server_addr, client_addr;  
    socklen_t client_len = sizeof(client_addr); 
    char *ip_address = argv[1];  
    int port = atoi(argv[2]);  
  
    // 创建TCP套接字  
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {  
        perror("socket creation failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 设置服务器地址信息  
    memset(&server_addr, 0, sizeof(server_addr));  
    server_addr.sin_family = AF_INET;  
    server_addr.sin_addr.s_addr = inet_addr(ip_address);  
    server_addr.sin_port = htons(port);  
  
    // 绑定套接字到服务器地址  
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {  
        perror("bind failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 监听套接字  
    if (listen(server_fd, 5) < 0) {  
        perror("listen failed");  
        exit(EXIT_FAILURE);  
    }  
  
    printf("Server listening on %s:%d...\n", ip_address, port);  
	//处理僵尸进程
	signal(SIGCHLD, SIG_IGN);

    // 接受客户端连接  
    if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) < 0) {  
        perror("accept failed");
        goto err1;
    }
    while (1) 
    {
        // 打印客户端信息  
        char client_ip[INET_ADDRSTRLEN];  
        inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);  
        printf("Client connected from %s:%d\n", client_ip, ntohs(client_addr.sin_port));  
        do_client(client_fd);
    }

err2:
    close(client_fd);
err1:
    close(server_fd);
    return NOERROR;  
}

修改了一下服务器程序

int do_client(int acceptfd)
{
	MSG msg;
    char rx_buffer[BUFFER_SIZE];
    char tx_buffer[BUFFER_SIZE];
    // 接收客户端消息  
    memset(rx_buffer, 0, BUFFER_SIZE);
    memset(tx_buffer, 0, BUFFER_SIZE);
    ssize_t bytes_read = recv(client_fd, rx_buffer, BUFFER_SIZE - 1, 0);  
    if (bytes_read < 0) {  
        perror("recv failed");  
        goto err2;
    }
    // 确保消息以换行符结尾,并打印接收到的消息  
    // if (bytes_read > 0 && rx_buffer[bytes_read - 1] != '\n') {  
    //     rx_buffer[bytes_read] = '\n';  
    //     rx_buffer[bytes_read + 1] = '\0';  
    // }  
    printf("Received message: %s", rx_buffer);  

    // 回复客户端消息  
    //strcpy(tx_buffer, "Hello, client!\n");
    if (send(client_fd, tx_buffer, strlen(tx_buffer), 0) < 0) 
    {  
        perror("send failed");  
    }
	return 0;
}

加了个结构体描述命令

编译咔咔报错

用信号报错要加这个

goto报错修改一下代码

if忘记括号了

局部变量名字用错了

msg定义了没用

因为借鉴了我以前写的ftp服务器所以双主函数报错了

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>

#define   N  32

#define  L  1   // user - list
#define  G  2   // user - get file
#define  P  3   // user - put file
#define  Q  4   // user - quit


// 定义通信双方的信息结构体
typedef struct {
	int type;                        //命令
	char data[1024];                 //文件具体内容
	char filename[256][256];         //文件名
	int len;                     //文件数量
	int error;
}MSG;



int do_get_time();
int do_client(int acceptfd, sqlite3 *db);
void do_list(int acceptfd, MSG *msg);
long back_size(const char *file);
void Download(int acceptfd, MSG *msg);
void put(int acceptfd, MSG *msg);
// ./server  192.168.3.196  10000
int main(int argc, const char *argv[])
{

	int sockfd;
	struct sockaddr_in  serveraddr;
	int n;
	MSG  msg;
	sqlite3 *db;
	int acceptfd;
	pid_t pid;

	if(argc != 3)
	{
		printf("Usage:%s serverip  port.\n", argv[0]);
		return -1;
	}


	if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0)
	{
		perror("fail to socket.\n");
		return -1;
	}

	bzero(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(argv[2]));

	if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
	{
		perror("fail to bind.\n");
		return -1;
	}

	// 将套接字设为监听模式
	if(listen(sockfd, 5) < 0)
	{
		printf("fail to listen.\n");
		return -1;
	}

	//处理僵尸进程
	signal(SIGCHLD, SIG_IGN);

	while(1)
	{
		if((acceptfd = accept(sockfd, NULL, NULL)) < 0)
		{
			perror("fail to accept");
			return -1;
		}

		if((pid = fork()) < 0)
		{
			perror("fail to fork");
			return -1;
		}
		else if(pid == 0)  // 儿子进程
		{
			//处理客户端具体的消息
			close(sockfd);
			do_client(acceptfd, db);
		}
		else  // 父亲进程,用来接受客户端的请求的
		{
			close(acceptfd);
		}
	}
	
	return 0;
}


int do_client(int acceptfd, sqlite3 *db)
{
	MSG msg;
	while(recv(acceptfd, &msg, sizeof(msg), 0) > 0)
	{
	  printf("type:%d\n", msg.type);
	   switch(msg.type)
	   {
	  	 case L:
			 do_list(acceptfd, &msg);
			 break;
		 case G:
			 Download(acceptfd, &msg);
			 break;
		 case P:
			 put(acceptfd, &msg);
			 break;
		 case Q:
			 //do_history(acceptfd, &msg, db);
			 
			//TODO
			break;
		 default:
			 printf("Invalid data msg.\n");
	   }
	}

	printf("client exit.\n");
	close(acceptfd);
	exit(0);

	return 0;
}

void do_list(int acceptfd, MSG *msg)
{
	DIR *d; //声明一个句柄
    struct dirent *file; //readdir函数的返回值就存放在这个结构体中
    struct stat sb;
	msg->len = 0;
    if(!(d = opendir("./")))
    {
        printf("error opendir %s!!!\n","./");
        exit(1);
    }
    while((file = readdir(d)) != NULL)
    {
        //把当前目录.,上一级目录..及隐藏文件都去掉,避免死循环遍历目录
        if(strncmp(file->d_name, ".", 1) == 0)
            continue;
        strcpy(msg->filename[msg->len++], file->d_name); //保存遍历到的文件名
    }
	closedir(d);


	if(send(acceptfd, msg, sizeof(MSG), 0) < 0)
	{
		perror("fail to send");
		return ;
	}
	printf("目录清单已经成功发送\n");
}

void Download(int acceptfd, MSG *msg)
{
	FILE* fd = NULL;
	size_t num_read;
	fd = fopen(msg->filename[0], "r"); // 打开文件
	if(fd == NULL)
	{
		perror("fopen");
		msg->error = 1;
		if(send(acceptfd, msg, sizeof(MSG), 0) < 0)
		{
			perror("fail to send");
			return ;
		}
		return;
	}
	msg->len = back_size(msg->filename[0]);
	num_read = fread(msg->data, 1, msg->len, fd); // 读文件内容
	printf("file is %d bit\n",msg->len);
	if (num_read < 0){ 
		printf("error in fread()\n");
		fclose(fd);
		return ;
	}
	msg->error = 0;
	if(send(acceptfd, msg, sizeof(MSG), 0) < 0)
	{
		perror("fail to send");
		fclose(fd);
		return ;
	}
	printf("%s已经成功发送\n",msg->filename[0]);
	fclose(fd);
}


void put(int acceptfd, MSG *msg)
{
	size_t num_write;
	FILE* fd = NULL;
	if(msg->error == 0){
		fd = fopen(msg->filename[0], "w"); // 打开文件
		if(fd == NULL)
		{
			perror("fopen");
			return ;
		}
		num_write = fwrite(msg->data, 1, msg->len, fd); //写文件内容
		if (num_write < 0){ 
			printf("error in fwrite()\n");
			fclose(fd);
			return ;
		}
		printf("%s创建并写入完成\n",msg->filename[0]);
		fclose(fd);
		return ;
	}else{
		printf(" server error\n");
		return ;	
	}	
}

long back_size(const char *file)
{
	//打开需要计算大小的文件
	FILE *frp = fopen(file,"r");
	if(NULL == frp)
	{
		perror("fopen");
		exit(EXIT_FAILURE);
	}
	//将文件指针置于文件末尾
	fseek(frp,0,SEEK_END);
	//计算文件大小并返回
	return ftell(frp);
}

好了这下没问题了

有毛病啊

while(1)的问题应该放到do_client做的

int do_client(int acceptfd)
{
	//MSG msg;
    char rx_buffer[BUFFER_SIZE];
    char tx_buffer[BUFFER_SIZE];
    while(1)
    {
        // 接收客户端消息  
        memset(rx_buffer, 0, BUFFER_SIZE);
        memset(tx_buffer, 0, BUFFER_SIZE);
        ssize_t bytes_read = recv(acceptfd, rx_buffer, BUFFER_SIZE - 1, 0);  
        if (bytes_read < 0) {  
            perror("recv failed");  
            return ERROR;
        }
        // 确保消息以换行符结尾,并打印接收到的消息  
        // if (bytes_read > 0 && rx_buffer[bytes_read - 1] != '\n') {  
        //     rx_buffer[bytes_read] = '\n';  
        //     rx_buffer[bytes_read + 1] = '\0';  
        // }  
        printf("Received message: %s", rx_buffer);  

        // 回复客户端消息  
        //strcpy(tx_buffer, "Hello, client!\n");
        if (send(acceptfd, tx_buffer, strlen(tx_buffer), 0) < 0) 
        {  
            perror("send failed");  
        }
    }
	return NOERROR;
}

新问题

改一下让他收到什么返回什么

经典缓冲区问题

退出也有问题

还缺一个快速重新绑定

这里也有问题

sendall只能发送字节序不能发送字符串

所以要这样处理一下

int do_client(int acceptfd)
{
	//MSG msg;
    char rx_buffer[BUFFER_SIZE];
    char tx_buffer[BUFFER_SIZE];
    while(1)
    {
        // 接收客户端消息  
        memset(rx_buffer, 0, BUFFER_SIZE);
        memset(tx_buffer, 0, BUFFER_SIZE);
        ssize_t bytes_read = recv(acceptfd, rx_buffer, BUFFER_SIZE - 1, 0);  
        if (bytes_read < 0) 
        {  
            perror("recv failed");  
            return ERROR;
        }
        else
        {
            /*确保消息以换行符结尾,并打印接收到的消息*/  
            if (bytes_read > 0 && rx_buffer[bytes_read - 1] != '\n') {  
                rx_buffer[bytes_read] = '\n';  
                rx_buffer[bytes_read + 1] = '\0';  
            }
            if ('Q' == rx_buffer[0])
            {
                printf("client quit....\n");
                return ERROR;
            }
            printf("Received message: %s", rx_buffer);  

            // 回复客户端消息  
            //strcpy(tx_buffer, "Hello, client!\n");
            if (send(acceptfd, rx_buffer, strlen(rx_buffer), 0) < 0) 
            {  
                perror("send failed");  
            }
        }
    }
	return NOERROR;
}

        但是这样改完有个问题消息内容是Q也会导致这面退出,我在想要留这个后门呢还是直接在python这面处理一下不允许直接发送Q。

        还是不允许发送好了,这个连接其实是程序自动的不是用户可输入的。加不加问题其实都不会存在。

现在就很完美了

最终版

#include "tcp.h"
#include "net.h"
#include "global.h"
/*
*author : xintianyu
*return : err num
*data   : 2024-4-10
-----------------------
*author : ???
*return : ???
*data   : ???
*/
int usage(int argc, char *argv[])
{ 
    if (argc != 3)
    {  
        printf("Usage: %s <ip_address> <port>\n", argv[0]);  
        return ERROR;  
    }
    else
    {
        return NOERROR;
    }
}

void do_nothing()
{
    /*void*/
}

/*
*author : xintianyu
*return : err num
*data   : 2024-4-10
-----------------------
*author : ???
*return : ???
*data   : ???
*/
int tcp_server(int argc, char *argv[]) 
{
    int server_fd, client_fd;  
    struct sockaddr_in server_addr, client_addr;  
    socklen_t client_len = sizeof(client_addr); 
    char *ip_address = argv[1];  
    int port = atoi(argv[2]);  
  
    // 创建TCP套接字  
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {  
        perror("socket creation failed");  
        exit(EXIT_FAILURE);  
    }  

    /*支持快速重新绑定*/
	int b_reuse = 1;
	setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));

    // 设置服务器地址信息  
    memset(&server_addr, 0, sizeof(server_addr));  
    server_addr.sin_family = AF_INET;  
    server_addr.sin_addr.s_addr = inet_addr(ip_address);  
    server_addr.sin_port = htons(port);  
  
    // 绑定套接字到服务器地址  
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {  
        perror("bind failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 监听套接字  
    if (listen(server_fd, 5) < 0) {  
        perror("listen failed");  
        exit(EXIT_FAILURE);  
    }  
  
    printf("Server listening on %s:%d...\n", ip_address, port);  
	//处理僵尸进程
	signal(SIGCHLD, SIG_IGN);

    // 接受客户端连接  
    if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) < 0) {  
        perror("accept failed");
        goto err1;
    }
    // 打印客户端信息  
    char client_ip[INET_ADDRSTRLEN];  
    inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);  
    printf("Client connected from %s:%d\n", client_ip, ntohs(client_addr.sin_port));
    if (ERROR == do_client(client_fd))
    {
        perror("client disconnect.....");
        goto err2;
    }

err2:
    close(client_fd);
err1:
    close(server_fd);
    return NOERROR;  
}

int do_client(int acceptfd)
{
	//MSG msg;
    char rx_buffer[BUFFER_SIZE];
    char tx_buffer[BUFFER_SIZE];
    int cmd;
    // 接收客户端消息
    memset(rx_buffer, 0, BUFFER_SIZE);
    memset(tx_buffer, 0, BUFFER_SIZE);
    while(1)
    {
        ssize_t bytes_read = recv(acceptfd, rx_buffer, BUFFER_SIZE - 1, 0);  
        if (bytes_read < 0) 
        {  
            perror("recv failed");  
            return ERROR;
        }
        else
        {
            /*确保消息以换行符结尾,并打印接收到的消息*/  
            if (bytes_read > 0 && rx_buffer[bytes_read - 1] != '\n') {  
                rx_buffer[bytes_read] = '\n';  
                rx_buffer[bytes_read + 1] = '\0';  
            }
            if ('Q' == rx_buffer[0])
            {
                printf("client quit....\n");
                return ERROR;
            }
            else
            {
                cmd = select_driver(rx_buffer);
            }
            printf("cmd is %d\n", cmd);
#if (STD_ON == DEBUG)
            printf("Received message: %s", rx_buffer);  

            // 回复客户端消息  
            //strcpy(tx_buffer, "Hello, client!\n");
            if (send(acceptfd, rx_buffer, strlen(rx_buffer), 0) < 0) 
            {  
                perror("send failed");  
            }
#endif/*STD_ON == DEBUG*/
        }
    }
	return NOERROR;
}


int select_driver(char * cmd)
{
    int opt = 0;
    if('@' == cmd[0])
    {
#if (STD_ON == DEBUG)
        printf("cmd[0] = @\n");
#endif/*STD_ON == DEBUG*/
    }
    else
    {
        printf("cmd[0] ERROR!!!\n");
        opt = ERROR;
    }
    opt = atoi(&cmd[1]);
    return opt;
}
import socket  
  
server_ip   = '192.168.5.110'
server_port = 8888 

# 设置服务器地址和端口  
server_address = (server_ip, server_port)
  
# 创建一个socket对象  
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
  
# 连接到服务器  
try:  
    client_socket.connect(server_address)  
    print(f'Connected to {server_address}')  
  
    # 接收用户输入并发送给服务器  
    while True:  
        try:  
            user_input = input('Enter command (or "exit" to quit): ')  
            if user_input.lower() == 'exit':
                cmd = 'Q'
                client_socket.sendall(cmd.encode())
                break
            while 'Q' == user_input:
                print(f'please input other string')
                user_input = input('Enter command (or "exit" to quit): ')
            client_socket.sendall(user_input.encode())  
  
            # 接收服务器的响应
            data = client_socket.recv(512)  
            print(f'Received: {data.decode()}')  
  
        except KeyboardInterrupt:  
            print('\nKeyboardInterrupt received, exiting...')  
            break  
        except ConnectionResetError:  
            print('\nConnection reset by server, exiting...')  
            break  
        except Exception as e:  
            print(f'An error occurred: {e}, trying to reconnect...')  
            client_socket.close()  # Close the socket if there's an error  
            client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # Create a new one  
            client_socket.connect(server_address)  # Reconnect to the server  
  
finally:  
    # 关闭连接  
    print('Closing socket')  
    client_socket.close()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇努力学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值