📄 server.c
字号:
#include <sys/socket.h>#include <netdb.h>#include <stdio.h>#include <string.h>#include <time.h>#include <malloc.h>#include <pthread.h>#define SERVER_PORT 8080 /*端口*/#define MAX_SIZE 25 /*滑动窗口的大小*/#define PACKET_SIZE 1400 /*每次读取的大小*/typedef struct packet{ int number; /*包的编号*/ int length; /*包的数据的大小*/ char buffer[PACKET_SIZE]; /*每次读取10*1024个字节*/}packet_t;typedef struct packet_control_block{ packet_t *pt;/*包的指针,每次用malloc进行产生,成功发送后释放*/ int state;/*包的状态---省略,在成功能发送就将其从Packet_State中删除即可*/ clock_t start;/*发送的起始时间,用以判断是否超时*/ int count;/*已被发送的次数,用以判断网络是否故障*/}PCB_t;typedef struct thread_parameter{ FILE *fp; int sockfd; struct sockaddr* addr_client;}paras_t;PCB_t Packet_State[MAX_SIZE] = {0}; /*构建一PCB控制块,包含5个元素,即滑动窗口的大小*/int Send_State = 1; /*当前文件的发送状态,是否发送完毕,以接受下一个请求*/void get_filename(char buf_filename[], char buf_request[]);void create_thread(FILE *fp, int sockfd, struct sockaddr *addr_client);void deal_request(char buf_request[], int sockfd, struct sockaddr *addr_client);void thread_send(void *ps);int main(){ int sockfd; if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { printf("socket error!!!\n"); return 1; } struct sockaddr_in addr_server; addr_server.sin_family = AF_INET; addr_server.sin_port = htons(SERVER_PORT); addr_server.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sockfd, (struct sockaddr*)&addr_server, sizeof(struct sockaddr)) == -1) { printf("bind error!!!\n"); return 1; } struct sockaddr_in addr_client; int addrlen = sizeof(struct sockaddr_in); while (1) { char buf_request[32] = {0}; if (recvfrom(sockfd, buf_request, 32, 0, (struct sockaddr*)&addr_client, &addrlen) <= 0) { printf("recvfrom error!!!\n"); return 1; } deal_request(buf_request, sockfd, (struct sockaddr*)&addr_client); } return 0;}/****************************************************用于从得到的字符串取出要获得文件名***************************************************/void get_filename(char buf_filename[], char buf_request[]){ char root_directory[] = "./file_read"; char *p1 = strstr(buf_request, " "); char *p2 = strchr(++p1, '\0'); int len = p2 - p1; memcpy(buf_filename, root_directory, strlen(root_directory)); memcpy(buf_filename + strlen(root_directory), p1, len);}/****************************************************在满足条件下创建一个新的线程进行发送数据操作***************************************************/void create_thread(FILE *fp, int sockfd, struct sockaddr *addr_client){ pthread_t pt; paras_t *ps = (paras_t *)malloc(sizeof(paras_t)); ps->fp = fp; ps->sockfd = sockfd; ps->addr_client = addr_client; pthread_create(&pt, NULL, (void *)thread_send, (void *)ps); pthread_detach(pt); /*分离线程*/}/****************************************************处理来自客户端的请求***************************************************/void deal_request(char buf_request[], int sockfd, struct sockaddr *addr_client){ if (!memcmp(buf_request, "GET", 3)) { if (Send_State)/*当前能够进行文件的发送*/ { char buf_filename[32] = {0}; get_filename(buf_filename, buf_request); FILE *fp; if ((fp = fopen(buf_filename, "rb")) == NULL) { printf("fopen error!!!\n"); return; } create_thread(fp, sockfd, addr_client); create_thread(fp, sockfd, addr_client); create_thread(fp, sockfd, addr_client); Send_State = 0; } } else { int i = 0; //for (;i < MAX_SIZE;i++) { //if (!(Packet_State[i].pt)) //break; int number1 = (Packet_State[i].pt)->number; char buf[8] = {0}; memcpy(buf, buf_request + 4, 5); int number2; sscanf(buf, "%d", &number2); if (number1 == number2) { if (!memcmp(buf_request, "ACK", 3)) { printf("the %d block has been sended successfully!!!\n", number1); //free(Packet_State[i].pt); //memset(&Packet_State[i], '\0', sizeof(PCB_t)); Packet_State[i].state = 1; } else if (!memcmp(buf_request, "ERROR", 5)) { Packet_State[i].count = 0; Packet_State[i].start = 0; } //break; } } }}/****************************************************线程函数,主要用于数据的发送***************************************************/void thread_send(void *ps){ FILE *fp = ((paras_t*)ps)->fp; int sockfd = ((paras_t*)ps)->sockfd; struct sockaddr addr_client = *(((paras_t*)ps)->addr_client); free(ps); /*释放内存*/ while (1) { int i = 0; int count = 0; int state = 1; /*判断是否读到文件末尾*/ static int next_packet = 0; /*记录当前块中最大的编号*/ for (;i < MAX_SIZE;i++) { if (Packet_State[i].state) { free(Packet_State[i].pt); Packet_State[i].pt = NULL; } if (!Packet_State[i].pt) { if (feof(fp)) { count++; if (count == MAX_SIZE) { Send_State = 1; return; } continue; } packet_t *pt = (packet_t *)malloc(sizeof(packet_t)); pt->number = next_packet; int len = fread(pt->buffer, 1, PACKET_SIZE, fp); pt->length = len; Packet_State[i].pt = pt; Packet_State[i].count = 0; Packet_State[i].start = 0; Packet_State[i].state = 0; next_packet++; } if (Packet_State[i].count > 10) { printf("net error!!!\n"); return; } int start = Packet_State[i].start; if (start == 0 || time(NULL) - start > 1) { printf("the %d block has been sended!!!", (Packet_State[i].pt)->number); int length = sendto(sockfd, Packet_State[i].pt, (Packet_State[i].pt)->length + 8, 0, &addr_client, sizeof(struct sockaddr)); Packet_State[i].start = time(NULL); Packet_State[i].count++; printf("the length is %d!!!\n\n", length - 8); } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -