一.广播
1.1发送
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<time.h>
#include<sys/wait.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line:%d\t%s\t%s\n",__LINE__,__FILE__,__func__);\
perror(msg);\
}while(0)
#define IP "192.168.2.255" //ifconfig出来的ubuntu本机ip
#define PORT 6666 //端口号 1024~49151
int main(int argc, const char *argv[])
{
//创建报式套接字
int cfd=socket(AF_INET,SOCK_DGRAM,0);
if(cfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("create socket success,cfd=%d __%d__\n",cfd, __LINE__);
//填充广播的地址信息结构体
//真实的地址信息结构体根据地址族制定:AF_INET:man 7 IP
struct sockaddr_in sin;
sin.sin_family =AF_INET; //必须填AF_INET
sin.sin_port =htons(PORT); //端口号 网络字节序
sin.sin_addr.s_addr =inet_addr(IP); //IP 网络字节序
socklen_t addrlen_1 =sizeof(sin);
int key=1;
if(setsockopt(cfd,SOL_SOCKET,SO_BROADCAST,&key,sizeof(key))<0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("设置广播成功,__%d__\n",__LINE__);
//struct sockaddr_in cin;//存储服务端的地址信息结构体
//socklen_t addrlen=sizeof(cin);
char buf[128]="";
//ssize_t res=0;
while(1)
{
//发送数据给广播
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
if( sendto(cfd,buf,sizeof(buf),0,(struct sockaddr *)&sin,addrlen_1) <0)
{
ERR_MSG("sendto");
return -1;
}
printf("client sendto success __%d__\n",__LINE__);
/*
//接受服务器传来的数据
res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr *)&cin,&addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
printf("[%s:%d]: %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),buf);
*/
}
//关闭套接字文件描述符
close(cfd);
return 0;
}
1.2接收
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<time.h>
#include<sys/wait.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line:%d\t%s\t%s\n",__LINE__,__FILE__,__func__);\
perror(msg);\
}while(0)
#define IP "192.168.2.255" //广播IP
#define PORT 6666 //端口号 1024~49151
int main(int argc, const char *argv[])
{
//创建报式套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("create socket success,sfd=%d __%d__\n",sfd, __LINE__);
//填充广播的地址信息结构体
//真实的地址信息结构体根据地址族制定:AF_INET:man 7 IP
struct sockaddr_in sin;
sin.sin_family =AF_INET; //必须填AF_INET
sin.sin_port =htons(PORT); //端口号 网络字节序
sin.sin_addr.s_addr =inet_addr(IP); //IP 网络字节序
//绑定广播的ip和端口 (必须绑定)
if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin)) <0)
{
ERR_MSG("bind");
return -1;
}
printf("bind success __%d__\n",__LINE__);
struct sockaddr_in cin;//存储接受的地址信息结构体
socklen_t addrlen=sizeof(cin);
char buf[128]="";
ssize_t res=0;
while(1)
{
bzero(buf,sizeof(buf));
//接受数据
res=recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr *)&cin,&addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
printf("[%s:%d]: %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),buf);
/*
//发送数据 谁发给我 我发给谁
strcat(buf,"555");
if( sendto(sfd,buf,sizeof(buf),0,(struct sockaddr *)&cin,addrlen) <0)
{
ERR_MSG("sendto");
return -1;
}
printf("sendto success __%d__\n",__LINE__);
*/
}
//关闭套接字文件描述符
close(sfd);
return 0;
}
二、组播
2.1发送
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<time.h>
#include<sys/wait.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line:%d\t%s\t%s\n",__LINE__,__FILE__,__func__);\
perror(msg);\
}while(0)
#define IP "224.1.2.3" //组播ip 224.0.0.0 239.255.255.255
#define PORT 6666 //端口号 1024~49151
int main(int argc, const char *argv[])
{
//创建报式套接字
int cfd=socket(AF_INET,SOCK_DGRAM,0);
if(cfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("create socket success,cfd=%d __%d__\n",cfd, __LINE__);
//填充服务器的地址信息结构体
//真实的地址信息结构体根据地址族制定:AF_INET:man 7 IP
struct sockaddr_in sin;
sin.sin_family =AF_INET; //必须填AF_INET
sin.sin_port =htons(PORT); //端口号 网络字节序
sin.sin_addr.s_addr =inet_addr(IP); //IP 网络字节序
socklen_t addrlen_1 =sizeof(sin);
struct sockaddr_in cin;//存储服务端的地址信息结构体
socklen_t addrlen=sizeof(cin);
char buf[128]="";
ssize_t res=0;
while(1)
{
//发送数据给服务器
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
if( sendto(cfd,buf,sizeof(buf),0,(struct sockaddr *)&sin,addrlen_1) <0)
{
ERR_MSG("sendto");
return -1;
}
printf("cli sendto success __%d__\n",__LINE__);
/*
//接受服务器传来的数据
res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr *)&cin,&addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
printf("[%s:%d]: %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),buf);
*/
}
//关闭套接字文件描述符
close(cfd);
return 0;
}
2.2接收
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<time.h>
#include<sys/wait.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line:%d\t%s\t%s\n",__LINE__,__FILE__,__func__);\
perror(msg);\
}while(0)
#define GROUP_IP "224.1.2.3" //组播IP,224.0.0.0~239.255.255.255
#define LOCAL_IP "192.168.2.130" //本机IP
#define PORT 6666 //端口号 1024~49151 与发送方的填充一致
int main(int argc, const char *argv[])
{
//1.创建报式套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("create socket success,sfd=%d __%d__\n",sfd, __LINE__);
//2.加入多播组
struct ip_mreqn team;
team.imr_multiaddr.s_addr =inet_addr(GROUP_IP);//组播IP
team.imr_address.s_addr =inet_addr(LOCAL_IP);
team.imr_ifindex =2;//默认索引号
int len=sizeof(team);
if(setsockopt(sfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&team,len)<0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("成功加入多播组,GROUP_IP=%s,__%d__\n",GROUP_IP,__LINE__);
//3.填充组播的地址信息结构体
//真实的地址信息结构体根据地址族制定:AF_INET:man 7 IP
struct sockaddr_in sin;
sin.sin_family =AF_INET; //必须填AF_INET
sin.sin_port =htons(PORT); //端口号 网络字节序
sin.sin_addr.s_addr =inet_addr(GROUP_IP); //IP 网络字节序
//4.绑定服务器的ip和端口 (必须绑定)
if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin)) <0)
{
ERR_MSG("bind");
return -1;
}
printf("bind success __%d__\n",__LINE__);
struct sockaddr_in cin;//存储客户端的地址信息结构体
socklen_t addrlen=sizeof(cin);
char buf[128]="";
ssize_t res=0;
while(1)
{
bzero(buf,sizeof(buf));
//5.接受数据
res=recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr *)&cin,&addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
printf("[%s:%d]: %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),buf);
/*
//发送数据 谁发给我 我发给谁
strcat(buf,"*-*");
if( sendto(sfd,buf,sizeof(buf),0,(struct sockaddr *)&cin,addrlen) <0)
{
ERR_MSG("sendto");
return -1;
}
printf("sendto success __%d__\n",__LINE__);
*/
}
//关闭套接字文件描述符
close(sfd);
return 0;
}
三、多进程并发服务器
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<time.h>
#include<sys/wait.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line:%d\t%s\t%s\n",__LINE__,__FILE__,__func__);\
perror(msg);\
}while(0)
#define IP "192.168.2.130" //ifconfig出来的ubuntu本机ip
#define PORT 6666 //端口号 1024~49151
int deal_cli_msg(int newfd,struct sockaddr_in cin);
void handler(int sig)
{
while(waitpid(-1,NULL,WNOHANG)>0)
{
printf("回收一个进程\n");
}
}
int main(int argc, const char *argv[])
{
//捕获(17)SIGCHLD信号
if(signal(SIGCHLD,handler)==SIG_ERR)
{
ERR_MSG("signal");
return -1;
}
//1.创建流式套接字
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("允许端口快速重用成功 __%d__\n", __LINE__);
//2.填充服务器的地址信息结构体,给bind函数绑定
//真实的地址信息结构体根据地址族制定:AF_INET:man 7 ip
struct sockaddr_in sin;
sin.sin_family =AF_INET; //必须填AF_INET
sin.sin_port =htons(PORT); //端口号 网络字节序
sin.sin_addr.s_addr =inet_addr(IP); //IP 网络字节序
//3.绑定服务器的ip和端口 (必须绑定)
if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin)) <0)
{
ERR_MSG("bind");
return -1;
}
printf("bind success __%d__\n",__LINE__);
//4.将套接字设置为被动监听状态
if(listen(sfd,128)<0)
{
ERR_MSG("listen");
return -1;
}
printf("listen success __%d__\n",__LINE__);
struct sockaddr_in cin;//存储客户端的地址信息结构体
socklen_t addrlen=sizeof(cin);
int newfd=-1;
pid_t cpid=0;
while(1)
{
//获取连接成功后的新套接字文件描述符
//父进程只负责交互
newfd=accept(sfd,(struct sockaddr *)&cin,&addrlen);
if(newfd<0)
{
ERR_MSG("accept");
return -1;
}
printf("[%s:%d]客户端连接成功,newfd=%d, __%d__\n",\
inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,__LINE__);
cpid=fork();
if(cpid==0)
{
//子进程运行
close(sfd);
deal_cli_msg(newfd,cin);
exit(0);
}
else if(cpid>0)
{
close(newfd);
}
else
{
ERR_MSG("fork");
return -1;
}
}
close(sfd);
return 0;
}
int deal_cli_msg(int newfd,struct sockaddr_in cin)
{
//接受
char buf[128]="";
ssize_t res=0;
while(1)
{
bzero(buf,sizeof(buf));
res=recv(newfd,buf,sizeof(buf),0);
if(res<0)
{
ERR_MSG("recv");
return -1;
}
else if(res==0)
{
printf("客户端下线,newfd=%d\n",newfd);
break;
}
printf("newfd=%d:%s\n",newfd,buf);
//发送
strcat(buf,"*-*\n");
if(send(newfd,buf,sizeof(buf),0)<0)
{
ERR_MSG("send");
return -1;
}
printf("send success\n");
}
//关闭套接字文件描述符
close(newfd);
}
四、多线程并发服务器
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<time.h>
#include<sys/wait.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line:%d\t%s\t%s\n",__LINE__,__FILE__,__func__);\
perror(msg);\
}while(0)
#define IP "192.168.2.130" //ifconfig出来的ubuntu本机ip
#define PORT 6666 //端口号 1024~49151
//需要传入数据到线程中
struct climsg
{
int newfd;
struct sockaddr_in cin;
};
void *deal_cli_msg(void *arg);
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("允许端口快速重用成功 __%d__\n", __LINE__);
//填充服务器的地址信息结构体,给bind函数绑定
//真实的地址信息结构体根据地址族制定:AF_INET:man 7 ip
struct sockaddr_in sin;
sin.sin_family =AF_INET; //必须填AF_INET
sin.sin_port =htons(PORT); //端口号 网络字节序
sin.sin_addr.s_addr =inet_addr(IP); //IP 网络字节序
//绑定服务器的ip和端口 (必须绑定)
if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin)) <0)
{
ERR_MSG("bind");
return -1;
}
printf("bind success __%d__\n",__LINE__);
//将套接字设置为被动监听状态
if(listen(sfd,128)<0)
{
ERR_MSG("listen");
return -1;
}
printf("listen success __%d__\n",__LINE__);
struct sockaddr_in cin;//存储客户端的地址信息结构体
socklen_t addrlen=sizeof(cin);
int newfd=-1;
pthread_t tid=0;
struct climsg info;
while(1)
{
//获取连接成功后的新套接字文件描述符
newfd=accept(sfd,(struct sockaddr *)&cin,&addrlen);
if(newfd<0)
{
ERR_MSG("accept");
return -1;
}
printf("[%s:%d]客户端连接成功,newfd=%d, __%d__\n",\
inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,__LINE__);
info.newfd=newfd;
info.cin=cin;
//运行到当前位置,代表有客户端连接
if(pthread_create(&tid,NULL,deal_cli_msg,&info)!=0)
{
fprintf(stderr,"pthread_create failed __%d__\n",__LINE__);
return -1;
}
//分离线程
pthread_detach(tid);
}
close(sfd);
return 0;
}
//线程处理函数
void *deal_cli_msg(void *arg)
{
int newfd=((struct climsg *)arg)->newfd;
struct sockaddr_in cin=((struct climsg *)arg)->cin;
//接受
char buf[128]="";
ssize_t res=0;
while(1)
{
bzero(buf,sizeof(buf));
res=recv(newfd,buf,sizeof(buf),0);
if(res<0)
{
ERR_MSG("recv");
break;
}
else if(res==0)
{
printf("客户端下线,newfd=%d\n",newfd);
break;
}
printf("newfd=%d:%s\n",newfd,buf);
/*
printf("addrlen=%d\n",addrlen);
printf("客户端ip=%s\n",inet_ntoa(cin.sin_addr));
*/
//发送
strcat(buf,"*-*\n");
if(send(newfd,buf,sizeof(buf),0)<0)
{
ERR_MSG("send");
break;
}
printf("send success\n");
}
//关闭套接字文件描述符
close(newfd);
}
五、TFTP服务器上传
//上传文件
int upload_file(int cfd,struct sockaddr_in sin)
{
socklen_t addrlen =sizeof(sin);//地址信息结构体大小
char buf[516]="";
ssize_t res=0;
int count;
char file_name[20]="";
printf("请输入上传的文件名:");
scanf("%s",file_name);
getchar();
//上传请求包
int size=sprintf(buf,"%c%c%s%c%s%c",0,2,file_name,0,"octet",0);
if( sendto(cfd,buf,size,0,(struct sockaddr *)&sin,addrlen) <0)
{
ERR_MSG("sendto");
return -1;
}
printf("client sendto upload success __%d__\n",__LINE__);
//打开文件读取权限
int fd=open(file_name,O_RDONLY);
unsigned short num=0;//记录数据包的编号
//循环发送数据包,接受ACK
while(1)
{
bzero(buf,sizeof(buf));
res=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr *)&sin,&addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
if(buf[1]==4)
{
//构造数据包
*((unsigned short *)buf)=htons(3);
*((unsigned short *)(buf+2))=htons(num+1);
res=read(fd,buf+4,512);
//发送数据包
count=sendto(cfd,buf,res+4,0,(struct sockaddr *)&sin,addrlen);
if(count<0)
{
ERR_MSG("sendto");
return -1;
}
printf("sendto success __%d__\n",__LINE__);
if(res<512)
{
printf("文件上传成功\n");
break;
}
num++;
}
if(buf[1]==5)
{
//错误包
printf("upload failed:%s\n",buf+4);
break;
}
}
//文件描述符
close(fd);
}
运行效果