本期没想好怎么排版以流水账形式展示了
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()