1. 广播,组播代码重新写一遍
#include <myhead.h>
#define IP "192.168.123.255"
int main(int argc,const char *argv[])
{
int sfd = socket(AF_INET,SOCK_DGRAM,0);//获取套接字文件
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
int opt = 1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0)//允许端口快速重用
{
ERR_MSG("setsockopt");
return -1;
}
if(setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)) < 0)//允许广播
{
ERR_MSG("setsockopt");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);//设置接受方端口
addr.sin_addr.s_addr = inet_addr(IP); //设置广播ip
while(1)
{
char a[20]="";
printf("输入内容:");
scanf("%s",a);
sendto(sfd,a,sizeof(a),0,(struct sockaddr *)&addr,sizeof(addr));//发送数据
}
close(sfd);
return 0;
}
#include <myhead.h>
#define IP "192.168.123.255"
int main(int argc,const char *argv[])
{
int sfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字文件
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
int opt = 1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0)//允许端口快速重用
{
ERR_MSG("setsockopt");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);//设置绑定的端口
addr.sin_addr.s_addr = inet_addr(IP);//设置广播ip
socklen_t addrlen = sizeof(addr);
if(bind(sfd,(struct sockaddr *)&addr,sizeof(addr)))//绑定端口和ip
{
ERR_MSG("bind");
return -1;
}
puts("bind success");
while(1)
{
char a[128]="";
struct sockaddr_in fs;
socklen_t fslen = sizeof(fs);
recvfrom(sfd,a,sizeof(a),0,(struct sockaddr *)&fs,&fslen);//接受数据,并获得发送方的ip和端口
printf("[%s:%d] %s\n",inet_ntoa(fs.sin_addr),ntohs(fs.sin_port),a);
}
close(sfd);
return 0;
}
#include <myhead.h>
#define IP "224.1.2.3"
int main(int argc,const char *argv[])
{
int sfd = socket(AF_INET,SOCK_DGRAM,0);//设置套接字文件
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
int opt = 1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0)//设置端口被快速重用
{
ERR_MSG("setsockopt");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);//设置端口
addr.sin_addr.s_addr = inet_addr(IP);//设置组播ip
while(1)
{
char a[128]="";
printf("输入内容:");
fgets(a,sizeof(a),stdin);
a[strlen(a)-1] = '\0';
sendto(sfd,a,sizeof(a),0,(struct sockaddr *)&addr,sizeof(addr));//发送数据
}
close(sfd);
return 0;
}
#include <myhead.h>
#define IP "224.1.2.3"
int main(int argc,const char *argv[])
{
int sfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字文件
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
int opt = 1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0)//允许端口被快速重用
{
ERR_MSG("setsockopt");
return -1;
}
struct ip_mreqn ipopt;
ipopt.imr_multiaddr.s_addr = inet_addr(IP);//设置组播ip
ipopt.imr_address.s_addr = inet_addr("192.168.122.183");//设置本地ip
ipopt.imr_ifindex = 0;//设置网卡设备号
if(setsockopt(sfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&ipopt,sizeof(ipopt)) < 0)//设置加入组播
{
ERR_MSG("setsockopt");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);//设置端口
addr.sin_addr.s_addr = inet_addr(IP);//组播ip
socklen_t addrlen = sizeof(addr);
if(bind(sfd,(struct sockaddr *)&addr,sizeof(addr)))//绑定ip和端口
{
ERR_MSG("bind");
return -1;
}
puts("bind success");
while(1)
{
char a[128]="";
struct sockaddr_in fs;
socklen_t fslen = sizeof(fs);
recvfrom(sfd,a,sizeof(a),0,(struct sockaddr *)&fs,&fslen);//接收数据
printf("[%s:%d] %s\n",inet_ntoa(fs.sin_addr),ntohs(fs.sin_port),a);
}
close(sfd);
return 0;
}
2. 多进程通过模型自己写一遍
#include <myhead.h>
#define ERR_MSG(msg) fprintf(stderr,"%d\n",__LINE__);perror(msg);
#define IP "192.168.122.183"
int delclimsg(int newfd,const struct sockaddr_in *addr)
{
while(1)
{
char buf[128] = "";
ssize_t res = recv(newfd,buf,sizeof(buf),0);//读取信息
if(res < 0)
{
ERR_MSG("recv");
return -1;
}
else if(res == 0)
{
printf("[%s:%d] 客户端:%d 下线\n",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),newfd);
break;
}
printf("[%s:%d] 客户端:%d 的消息:%s\n",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),newfd,buf);
res = send(newfd,buf,sizeof(buf),0);//发送信息
if(res < 0)
{
ERR_MSG("send");
return -1;
}
}
}
void signal_hadler(int signo)//回收子进程资源
{
while(waitpid(-1,NULL,WNOHANG) > 0);
}
int main(int argc,const char *argv[])
{
int sfd = socket(AF_INET,SOCK_STREAM,0);//创建套接子文件
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
//允许端口快速被重用
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("允许端口快速被重用成功\n");
struct sockaddr_in sai;
sai.sin_family = AF_INET;//协议族
sai.sin_port = htons(6666);//服务器端口
sai.sin_addr.s_addr = inet_addr(IP);//服务器IP
if(bind(sfd,(struct sockaddr *)&sai,sizeof(struct sockaddr_in)) < 0)//绑定ip和端口
{
ERR_MSG("bind");
return -1;
}
puts("bind success");
if(listen(sfd,128) < 0)//设置为被动监听状态,最大128
{
ERR_MSG("listen");
return -1;
}
puts("listen success");
struct sockaddr_in addr;
socklen_t addrlen=sizeof(addr);
signal(SIGCHLD,signal_hadler);//当子进程死亡时捕获信号
while(1)
{
int newfd = accept(sfd,(struct sockaddr *)&addr,&addrlen);//等待客户端连接,返回客户端的文件描述符和ip端口等
if(newfd <0)
{
ERR_MSG("accept");
return -1;
}
printf("[%s:%d]newfd = %d 客户端连接成功\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port),newfd);
if(fork()==0)//子进程负责和客户端通信
{
close(sfd);
delclimsg(newfd,&addr);
close(newfd);
exit(0);
}
close(newfd);
}
if(close(sfd) < 0)
{
ERR_MSG("close");
return -1;
}
return 0;
}
3. 多线程代码写一遍,能否将newfd定义成全局(不行,找原因)
#include <myhead.h>
#define ERR_MSG(msg) fprintf(stderr,"%d\n",__LINE__);perror(msg);
#define IP "192.168.122.183"
typedef struct{
int newfd;
struct sockaddr_in *addr;
}cliin;//定义结构体用于线程传参
void *delclimsg(void *arg)
{
cliin *cli = arg;
int newfd = cli->newfd;
const struct sockaddr_in *addr = cli->addr;
while(1)
{
char buf[128] = "";
ssize_t res = recv(newfd,buf,sizeof(buf),0);//读取信息
if(res < 0)
{
ERR_MSG("recv");
break;
}
else if(res == 0)
{
printf("[%s:%d] 客户端:%d 下线\n",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),newfd);
break;
}
printf("[%s:%d] 客户端:%d 的消息:%s\n",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),newfd,buf);
res = send(newfd,buf,sizeof(buf),0);//发送信息
if(res < 0)
{
ERR_MSG("send");
break;
}
}
close(newfd);
}
int main(int argc,const char *argv[])
{
int sfd = socket(AF_INET,SOCK_STREAM,0);//创建套接子文件
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
//允许端口快速被重用
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("允许端口快速被重用成功\n");
struct sockaddr_in sai;
sai.sin_family = AF_INET;//协议族
sai.sin_port = htons(6666);//服务器端口
sai.sin_addr.s_addr = inet_addr(IP);//服务器IP
if(bind(sfd,(struct sockaddr *)&sai,sizeof(struct sockaddr_in)) < 0)//绑定ip和端口
{
ERR_MSG("bind");
return -1;
}
puts("bind success");
if(listen(sfd,128) < 0)//设置为被动监听状态,最大128
{
ERR_MSG("listen");
return -1;
}
puts("listen success");
struct sockaddr_in addr;
socklen_t addrlen=sizeof(addr);
while(1)
{
int newfd = accept(sfd,(struct sockaddr *)&addr,&addrlen);//等待客户端连接,返回客户端的文件描述符和ip端口等
if(newfd <0)
{
ERR_MSG("accept");
return -1;
}
printf("[%s:%d]newfd = %d 客户端连接成功\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port),newfd);
pthread_t tid;
cliin cli = {newfd,&addr};
if(pthread_create(&tid,NULL,delclimsg,&cli) < 0)//创建线程用于进行通信
{
fprintf(stderr,"pthread_create error");
return -1;
}
pthread_detach(tid);//线程设置为分离态
}
if(close(sfd) < 0)
{
ERR_MSG("close");
return -1;
}
return 0;
}
不能定义为全局变量,后面accept的newfd会覆盖之前的newfd,导致线程无法和之前的客户端进行通信。
4. 上传下载写完。
#include <myhead.h>
#define IP "192.168.122.79"
typedef struct{
uint16_t opcode;
uint16_t block;
uint8_t data[512];
}datapag;
typedef struct{
uint16_t opcode;
uint16_t block;
}ack;
int upload(int cfd,const struct sockaddr_in *addr,int addrlen)
{
char fname[20] = "";
printf("输入文件名:");
scanf("%s",fname);
int f = open(fname,O_RDONLY);//打开需要上传的文件
if(f < 0)
{
ERR_MSG("open");
return -1;
}
char buf[128]="";//写请求
char *ptr = buf;
*(uint16_t *)ptr = htons(2);
ptr+=2;
strcpy(ptr,fname);
ptr += strlen(fname)+1;
strcpy(ptr,"octet");
if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr *)addr,addrlen) < 0)//发送请求
{
ERR_MSG("sendto");
return -1;
}
while(1)
{
ack a;
struct sockaddr_in ser;
socklen_t serlen = sizeof(ser);
if(recvfrom(cfd,&a,sizeof(a),0,(struct sockaddr *)&ser,&serlen) < 0)//接受cak
{
ERR_MSG("sendto");
return -1;
}
datapag dg = {htons(3),htons(ntohs(a.block)+1)};//block加1
ssize_t len = read(f,dg.data,sizeof(dg.data));//读取512字节的数据放入数据包
if(len < 0)
{
ERR_MSG("read");
return -1;
}
if(sendto(cfd,&dg,len+4,0,(struct sockaddr *)&ser,serlen) < 0)//发送数据包
{
ERR_MSG("sendto");
return -1;
}
if(len < sizeof(dg.data))//完成
{
break;
}
}
close(f);
}
int download(int cfd,const struct sockaddr_in *addr,int addrlen)
{ //发送数据
char buf[128]="";
char *ptr = buf;
*(uint16_t *)ptr = htons(1);
ptr += 2;
char fname[20] = "";
printf("输入文件名:");
scanf("%s",fname);
strcpy(ptr,fname);
ptr += strlen(fname)+1;
strcpy(ptr,"octet");
if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr *)addr,addrlen) < 0)//发送请求
{
ERR_MSG("sendto");
return -1;
}
ack a={htons(4),htons(0)};//ack
int f = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0664);//打开文件往里面放数据
if(f<0)
{
ERR_MSG("open file");
return -1;
}
while(1)
{
struct sockaddr_in ser;
socklen_t serlen = sizeof(ser);
datapag pg;
printf("1\n");
ssize_t len = recvfrom(cfd,&pg,sizeof(pg),0,(struct sockaddr *)&ser,&serlen);//获得数据包和服务器地址
if (len < 0)
{
ERR_MSG("recvfrom");
return -1;
}
a.block = pg.block;//修改ack的块编号
printf("2 %d\n",ntohs(a.block));
if(sendto(cfd,&a,sizeof(a),0,(struct sockaddr *)&ser,serlen) < 0)//发送ack
{
ERR_MSG("sendto");
return -1;
}
printf("3 %ld\n",len);
if(write(f,pg.data,len - 4) < 0)//往文件中写数据
{
ERR_MSG("write");
return -1;
}
if(len-4 < 512)//数据不足512则执行结束
{
puts("传输完成");
close(f);
return 0;
}
}
}
int main(int argc,const char *argv[])
{
//创建套接字
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd < 0)
{
ERR_MSG("socket");
return -1;
}
puts("socket success");
struct sockaddr_in addr;//服务器地址
addr.sin_family = AF_INET;
addr.sin_port = htons(69);
addr.sin_addr.s_addr = inet_addr(IP);
socklen_t addrlen = sizeof(addr);
char c = 0;
while(1)
{
puts("1.上传");
puts("2.下载");
puts("3.退出");
c = getchar();
while(getchar()!='\n');
if(c=='3')
break;
switch(c)
{
case '1':
upload(cfd,&addr,addrlen);//上传函数
break;
case '2':
download(cfd,&addr,addrlen);//下载函数
break;
}
}
//关闭文件
close(cfd);
return 0;
}