#include<head.h>
#define SER_PORT 69
#define SER_IP "192.168.106.1"
#define CIL_PORT 5555
#define CIL_IP "192.168.106.128"
int main(int argc, char const *argv[])
{
int cfd=socket(AF_INET,SOCK_DGRAM,0);
if(cfd==-1)
{
perror("socket error");
return -1;
}
printf("cfd=%d\n",cfd);
//2.向服务器发送下载请求
char buf[516]="";
char arr[10]="";
int a;
while(1)
{
printf("<<<1.下载>>>\n");
printf("<<<2.上传>>>\n");
printf("<<<3.退出>>>\n");
printf("请输入要执行的操作:");
scanf("%d",&a);
switch(a)
{
case 1://下载
{
bzero(buf,sizeof(buf));
short *p1=buf; //操作码
*p1=htons(1);
printf("请输入要下载的文件名:");
getchar();
fgets(arr,sizeof(arr),stdin);
arr[strlen(arr)-1]=0;
char *p2=buf+2; //文件名
strcpy(p2,arr);
char *p4=p2+strlen(p2)+1; //模式位
strcpy(p4,"octet");
int size=2+strlen(p2)+strlen(p4)+2; //请求包总长度
//将请求包发送给服务器
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(SER_PORT);
sin.sin_addr.s_addr=inet_addr(SER_IP);
sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin));
printf("发送请求成功\n");
int fd=-1;//创建一个无效文件描述符
unsigned short num=1;
ssize_t res=0;
socklen_t addrlen = sizeof(sin); //接受地址长度
while(1)
{
bzero(buf,sizeof(buf));
res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
if(buf[1]==3)
{
if(*(unsigned short*)(buf+2)==htons(num))
{
num++;
if(fd==-1)
{
fd=open(arr,O_CREAT|O_TRUNC|O_WRONLY,0664);
if(fd<0)
{
perror("open error");
return -1;
}
}
write(fd,buf+4,res-4);
buf[1]=4;
sendto(cfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin));
if(res<516)
{
printf("文件下载完毕\n");
break;
}
}
}
}
close(fd);
}break;
case 2://上传
{
bzero(buf,sizeof(buf));
short *p1=buf; //操作码
*p1=htons(2);
printf("请输入要上传的文件名:");
getchar();
fgets(arr,sizeof(arr),stdin);
arr[strlen(arr)-1]=0;
char *p2=buf+2; //文件名
strcpy(p2,arr);
char *p4=p2+strlen(p2)+1; //模式位
strcpy(p4,"octet");
int size=2+strlen(p2)+strlen(p4)+2; //请求包总长度
//将请求包发送给服务器
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(SER_PORT);
sin.sin_addr.s_addr=inet_addr(SER_IP);
sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin));
printf("发送请求成功\n");
unsigned short num=0;
int fd=open(arr,O_RDONLY);
ssize_t res=0;
socklen_t addrlen = sizeof(sin); //接受地址长度
while(1)
{
bzero(buf,sizeof(buf));
recvfrom(cfd,buf,4,0,(struct sockaddr*)&sin,&addrlen);
if(buf[1]==4)
{
if(*(unsigned short*)(buf+2)==htons(num))
{
buf[1]=3;
num++;
*(unsigned short*)(buf+2)=htons(num);
res=read(fd,buf+4,sizeof(buf)-4);
if(res==0)
{
break;
}
sendto(cfd,buf,sizeof(buf),0,(struct
sockaddr*)&sin,sizeof(sin));
}
}
}
close(fd);
printf("上传完毕\n");
}break;
case 3:goto END;
}
}
END:
close(cfd);
return 0;
}
下载效果图
上传效果图
服务端
#include "talk.h"
int main(int argc, const char *argv[])
{
int sfd;
if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("socket error");
}
printf("sfd=%d\n",sfd);
struct sockaddr_in sin;
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(SER_IP);
sin.sin_port = htons(SER_PORT);
socklen_t sin_len = sizeof(sin);
if (bind(sfd, (struct sockaddr *)&sin, sin_len) == -1)
{
perror("bind error");
}
struct sockaddr_in cin;
bzero(&cin, sizeof(cin));
socklen_t cin_len = sizeof(cin);
msgTyp msg;
//创建进程
pid_t pid = fork();
if (pid<0)
{
perror("fork error");
}
else if (pid == 0)
{
//子进程
//接受数据并处理
NodePtr L = NULL;
list_create(&L);
L->next = NULL;
while (1)
{
bzero(&msg, sizeof(msg));
bzero(&cin, sizeof(cin));
if ((recvfrom(sfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, &cin_len)) == -1)
{
perror("recvfrom error");
}
printf("%s : %s\n", msg.name, msg.txt);
switch (msg.code)
{
case 'L':
denglu(sfd, msg, cin, L);
break;
case 'C':
qunliao(sfd, msg, cin, L);
break;
case 'Q':
tuichu(sfd, msg, cin, L);
break;
}
}
}
else if (pid > 0)
{
//父进程
//发系统消息
msg.code='C';
strcpy(msg.name,"server");
while(1)
{
fgets(msg.txt,128,stdin);
msg.txt[strlen(msg.txt)-1]='\0';
if(sendto(sfd,&msg,sizeof(msgTyp),0,(struct sockaddr *)&sin,sin_len)==-1)
{
perror("sendto error");
}
}
}
close(sfd);
return 0;
}
客户端
#include "talk.h"
//宏定义打印错误信息
int main(int argc, const char *argv[])
{
//创建套接字
int sfd;
if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("socket error");
}
//创建服务器网络信息结构体
struct sockaddr_in sin;
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(SER_IP);
sin.sin_port = htons(SER_PORT);
socklen_t sin_len = sizeof(sin);
//给服务器发送登录数据包
msgTyp msg;
bzero(&msg,sizeof(msgTyp));
msg.code = 'L';
printf("请输入用户名:");
fgets(msg.name, 32, stdin);
msg.name[strlen(msg.name) - 1] = '\0';
strcpy(msg.txt, "加入群聊");
if (sendto(sfd, &msg, sizeof(msgTyp), 0, (struct sockaddr *)&sin, sin_len) == -1)
{
perror("sendto error");
}
//创建父子进程
pid_t pid;
pid = fork();
if (pid == -1)
{
perror("fork error");
}
else if (pid == 0)
{
//子进程
//接受数据并处理
while (1)
{
bzero(&msg, sizeof(msg));
if (recvfrom(sfd, &msg, sizeof(msgTyp), 0, NULL, NULL) == -1)
{
perror("recvfrom error");
}
printf("%s:%s\n", msg.name, msg.txt);
}
}
else if (pid > 0)
{
//父进程
//发送消息
while (1)
{
msg.code = 'C';
fgets(msg.txt, 128, stdin);
msg.txt[strlen(msg.txt) - 1] = '\0';
if (strcmp(msg.txt, "quit") == 0)
{
msg.code = 'Q';
strcpy(msg.txt, "退出群聊");
}
if (sendto(sfd, &msg, sizeof(msgTyp), 0, (struct sockaddr *)&sin, sin_len) == -1)
{
perror("sendto error");
}
if (strcmp(msg.txt, "退出群聊") == 0)
{
break;
}
}
kill(pid,SIGKILL);
wait(NULL);
close(sfd);
}
return 0;
}
talk.c和talk.h
#include "talk.h"
//链表创建
void list_create(NodePtr*L)
{
*L = (NodePtr)malloc(sizeof(Node));
}
//登录
int denglu(int sfd, msgTyp msg, struct sockaddr_in cin, NodePtr L)
{
//遍历链表将登录信息发送给所以人
NodePtr p = L;
while (p->next != NULL)
{
p = p->next;
if (sendto(sfd, &msg, sizeof(msgTyp), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1)
{
perror("recvfrom error");
}
}
//头插
NodePtr q = NULL;
list_create(&q);
q->c_addr = cin;
q->next = L->next;
L->next = q;
return 0;
}
int qunliao(int sfd, msgTyp msg, struct sockaddr_in cin, NodePtr L)
{
//遍历链表
NodePtr p = L;
while (p->next != NULL)
{
p = p->next;
//判断链表是否是自己
if (memcmp(&(p->c_addr), &cin, sizeof(cin)))
{
if (sendto(sfd, &msg, sizeof(msgTyp), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1)
{
perror("recvfrom error");
}
}
}
return 0;
}
//退出群聊
int tuichu(int sfd, msgTyp msg, struct sockaddr_in cin, NodePtr L)
{
NodePtr p = L;
while (p->next != NULL)
{
//判断链表是否是自己
if (memcmp(&(p->next->c_addr), &cin, sizeof(cin)))
{
p = p->next;
if (sendto(sfd, &msg, sizeof(msgTyp), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1)
{
perror("recvfrom error");
}
}
else
{
NodePtr p = p->next;
p->next = p->next;
p->next = NULL;
free(p);
p = NULL;
}
}
return 0;
}
#include <head.h>
typedef struct
{
char code;
char name[32];
char txt[128];
} msgTyp;
//链表结构体
typedef struct Node
{
struct sockaddr_in c_addr;
struct Node* next;
} Node,*NodePtr;
//创建链表
void list_create(NodePtr*L);
//登录
int denglu(int sfd, msgTyp msg, struct sockaddr_in cin, NodePtr L);
//发送群消息
int qunliao(int sfd, msgTyp msg, struct sockaddr_in cin, NodePtr L);
//退出
int tuichu(int sfd, msgTyp msg, struct sockaddr_in cin, NodePtr L);
#define SER_PORT 9999
#define SER_IP "192.168.106.128"
#define CLI_PORT 6666
#define CLI_IP "192.168,106.128"
效果图
思维套图