基于UDP实现的简单客户端服务端文件传输示例
程序员文章站
2022-06-06 14:10:43
...
基于UDP实现的简单客户端服务端文件传输示例
在翻阅过去代码时发现这个示例中包含的知识点挺多,在实现UDP通信的同时,也涉及到对信号处理、线程、自旋锁等的处理,不妨整理出来留做参考。
head.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#define MAXSIZE 100
#define BUFFNUM 5
#define MSG_FILENAME 1 //文件名
#define MSG_CONTENT 2 //文件内容
#define MSG_ACK 3 //回复
#define MSG_DONE 4 //正常发送完毕
#define MSG_EXCEPTION 5 //异常结束
struct msg {
int type;
int data_len;
char data[MAXSIZE];
};
client.c
#include "head.h"
#define FILEPATH "/etc/passwd"
pthread_spinlock_t spinlock;
pthread_t t_read;
FILE *fp;
int sockfd, retval;
char buff[BUFFNUM][MAXSIZE];
struct msg send_buff, recv_buff;
struct sockaddr_in serveraddr;
int head = 0;
int rear = 0;
int count = 0;
void sendinitname(struct msg *s)
{
char filename[256] = {"\0"};
s->type = MSG_FILENAME;
printf("input filename:");
scanf("%s",filename);
strcpy(s->data, filename);
}
void sendinitcontent(struct msg *s)
{
s->type = MSG_CONTENT;
strcpy(s->data, buff[head]);
}
void sendexit_done(struct msg *s)
{
s->type = MSG_DONE;
}
void sendexit_exception(struct msg *s)
{
s->type = MSG_EXCEPTION;
}
void sigexception(int signum)
{
struct msg tmp;
memset(&tmp, 0, sizeof(tmp));
sendexit_exception(&tmp);
if(sendto(sockfd, (void *)&tmp, sizeof(tmp), 0,
(struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
{
perror("send");
exit(1);
}
exit(1);
}
void *readthread(void *arg)
{
while(1)
{
if(head == rear)
{
while(count >= BUFFNUM) ;
}
memset(buff[rear], 0, sizeof(buff[rear]));
retval = fread(buff[rear], 1, MAXSIZE - 1, fp);
strcat(buff[rear], "\0");
if(retval != (MAXSIZE - 1))
{
if(feof(fp))
{
printf("read over\n");
rear = (rear + 1)%BUFFNUM;
pthread_spin_lock(&spinlock);
count++;
pthread_spin_unlock(&spinlock);
break;
}
printf("errno is: %d\n", errno);
exit(1);
}
rear = (rear + 1)%BUFFNUM;
pthread_spin_lock(&spinlock);
count++;
pthread_spin_unlock(&spinlock);
}
pthread_exit("read over");
}
int main(int argc, char *argv[])
{
int len = sizeof(socklen_t);
signal(SIGINT, sigexception);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
{
perror("socket");
exit(1);
}
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(2500);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
if((fp = fopen(FILEPATH, "r")) == NULL)
{
perror("fopen");
exit(1);
}
memset(&send_buff, 0, sizeof(send_buff));
memset(&recv_buff, 0, sizeof(recv_buff));
sendinitname(&send_buff);
printf("prepare send %s\n", FILEPATH);
if(sendto(sockfd, (void *)&send_buff, sizeof(struct msg), 0,
(struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
{
perror("send");
exit(1);
}
if(recvfrom(sockfd, (void *)&recv_buff, sizeof(struct msg), 0,
(struct sockaddr *)&serveraddr, &len) != -1)
{
if(recv_buff.type == MSG_ACK)
{
printf("recv from server: %s\n", recv_buff.data);
}
}
memset(&send_buff, 0, sizeof(send_buff));
printf("prepare send %s\n", FILEPATH);
pthread_spin_init(&spinlock, 0);
pthread_create(&t_read, NULL, readthread, NULL);
while(1)
{
memset(&send_buff, 0, sizeof(send_buff));
if(head == rear)
{
while(count <= 0);
}
sendinitcontent(&send_buff);
if(sendto(sockfd, (void *)&send_buff, sizeof(send_buff), 0,
(struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
{
perror("send");
exit(1);
}
if(feof(fp) && (count == 1))
{
memset(&send_buff, 0, sizeof(send_buff));
sendexit_done(&send_buff);
sendto(sockfd, (void *)&send_buff, sizeof(send_buff), 0,
(struct sockaddr *)&serveraddr, sizeof(serveraddr));
printf("send over\n");
break;
}
head = (head + 1)%BUFFNUM;
pthread_spin_lock(&spinlock);
count--;
pthread_spin_unlock(&spinlock);
}
pthread_join(t_read, NULL);
pthread_spin_destroy(&spinlock);
fclose(fp);
close(sockfd);
return 0;
}
server.c
#include "head.h"
int sockfd;
FILE *fp;
char buff[BUFFNUM][MAXSIZE];
struct msg recv_buff, send_buff;
struct sockaddr_in serveraddr, clientaddr;
int head = 0;
int rear = 0;
int count = 0;
int flag = 0;
pthread_t t_write;
pthread_spinlock_t spinlock;
char tmpfilename[256] = {"tmpfile"};
void exitserver(int signalnum)
{
printf("receive signalnum is %d\n", signalnum);
close(sockfd);
exit(0);
}
void *writethread(void *arg)
{
while(1)
{
if(head == rear)
{
while(count <= 0)
{
if(flag == 1)
break;
}
}
fp = fopen(tmpfilename, "a+");
if((fwrite(buff[head], 1,
strlen(buff[head]), fp)) == 0)
{
perror("fwrite");
exit(1);
}
fclose(fp);
head = (head + 1)%BUFFNUM;
if((flag == 1) && (count == 1))
{
printf("write over\n");
break;
}
pthread_spin_lock(&spinlock);
count--;
pthread_spin_unlock(&spinlock);
}
pthread_exit("write over");
}
int main(int argc, char *argv[])
{
int len = sizeof(socklen_t);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
{
perror("socket");
exit(1);
}
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(2500);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockfd, (struct sockaddr *)&serveraddr,
sizeof(serveraddr)) == -1)
{
perror("bind");
exit(1);
}
signal(SIGINT, exitserver);
pthread_spin_init(&spinlock, 0);
pthread_create(&t_write, NULL, writethread, NULL);
while(1)
{
memset(&recv_buff, 0, sizeof(recv_buff));
memset(&send_buff, 0, sizeof(send_buff));
if(recvfrom(sockfd, (void *)&recv_buff, sizeof(recv_buff), 0,
(struct sockaddr *)&clientaddr, &len) == -1)
{
perror("recv");
exit(1);
}
if(recv_buff.type == MSG_FILENAME) {
strcpy(tmpfilename, recv_buff.data);
fp = fopen(tmpfilename, "w");
send_buff.type = MSG_ACK;
strcpy(send_buff.data, "create file successfully");
send_buff.data_len = strlen(send_buff.data);
if((sendto(sockfd, (void *)&send_buff, sizeof(send_buff), 0,
(struct sockaddr *)&clientaddr, sizeof(clientaddr))) == -1)
{
perror("send");
exit(1);
}
fclose(fp);
}
else if(recv_buff.type == MSG_CONTENT) {
if(head == rear)
{
while(count >= BUFFNUM) ;
}
memset(buff[rear], 0, sizeof(buff[rear]));
strcpy(buff[rear], recv_buff.data);
rear = (rear + 1)%BUFFNUM;
pthread_spin_lock(&spinlock);
count++;
pthread_spin_unlock(&spinlock);
} else if(recv_buff.type == MSG_ACK) {
printf("recv mesg: %s\n", recv_buff.data);
} else if(recv_buff.type == MSG_DONE) {
flag = 1;
printf("client exit\n");
break;
} else if(recv_buff.type == MSG_EXCEPTION) {
flag = 1;
printf("EXCEPTION: client exit\n");
break;
}
}
pthread_join(t_write, NULL);
pthread_spin_destroy(&spinlock);
close(sockfd);
return 0;
}