今日任务
对于newfd的话,最好是另存然后传入给分支线程,避免父子线程操作同一个文件描述符
------------在tcp多线程服务端----------
如果使用全局变量,或者指针方式间接访问,会导致所有线程共用一份newfd和cin,那么newfd和cin会被覆盖
1.广播:
接收端
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>#define ERR_MSG(msg) do{\perror(msg);\fprintf(stderr,"__%d__",__LINE__);\
}while(0)
#define IP "192.168.125.255"
#define PORT 8888
/** function: 广播,接收方* @param [ in] * @param [out] * @return */int main(int argc, const char *argv[])
{//创建报式套接字int sfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd<0){ERR_MSG("socket");return -1;}puts("socket success");//绑定IIF(P和端口号(广播ip)struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(PORT);addr.sin_addr.s_addr=inet_addr(IP);socklen_t addrlen=sizeof(addr);if(bind(sfd,(struct sockaddr*)&addr,addrlen)<0){ERR_MSG("bind");}puts("bind success");//存储发送方地址消息struct sockaddr_in source_addr;socklen_t source_addrlen=sizeof(source_addr);//循环接受消息char buf[128]="";while(1){bzero(buf,sizeof(buf));int recv_res=recvfrom(sfd,&buf,sizeof(buf),0,(struct sockaddr*)&source_addr,&source_addrlen);if(recv_res<0){ERR_MSG("recvfrom");return -1;}puts("recvfrom success");printf("[%s:%d]:%s\n",inet_ntoa(source_addr.sin_addr),ntohs(source_addr.sin_port),buf);}//关闭close(sfd);return 0;
}
发送端
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>#define ERR_MSG(msg) do{\perror(msg);\fprintf(stderr,"__%d__",__LINE__);\
}while(0)
#define IP "192.168.125.255"
#define PORT 8888
/** function: 广播,发送方* @param [ in] * @param [out] * @return */int main(int argc, const char *argv[])
{//创建报式套接字int sfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd<0){ERR_MSG("socket");return -1;}puts("socket success");//设置允许广播int optval=1;//非0为允许socklen_t optlen=sizeof(optval);if(setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&optval,optlen)<0){ERR_MSG("setsockopt");return -1;}//IP和端口号(广播ip)struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(PORT);addr.sin_addr.s_addr=inet_addr(IP);socklen_t addrlen=sizeof(addr);//循环发送消息char buf[128]="";while(1){bzero(buf,sizeof(buf));printf("请输入>>>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]='\0';if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&addr,addrlen)<0){ERR_MSG("sendto");return -1;}puts("sendto success");}//关闭close(sfd);return 0;
}
2.组播
接收端
代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>#define ERR_MSG(msg) do{\perror(msg);\fprintf(stderr,"__%d__",__LINE__);\
}while(0)
#define IP "192.168.125.2"
#define PORT 8888
#define GRP_IP "224.1.2.3"
/** function: 组播:接收方* @param [ in] * @param [out] * @return */
int main(int argc, const char *argv[])
{//创建报式套接字int sfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd<0){ERR_MSG("socket");return -1;}puts("socket success");//加入多播组struct ip_mreqn mq;mq.imr_multiaddr.s_addr = inet_addr(GRP_IP); //组播IPmq.imr_address.s_addr = inet_addr(IP); //本机IP,ifconfigmq.imr_ifindex = 2; //网络设备索引号if(setsockopt(sfd,IPPROTO_IP, IP_ADD_MEMBERSHIP,&mq,sizeof(mq))<0){ERR_MSG("setsockopt");return -1;}//绑定IIF(P和端口号(广播ip)struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(PORT);addr.sin_addr.s_addr=inet_addr(GRP_IP);socklen_t addrlen=sizeof(addr);if(bind(sfd,(struct sockaddr*)&addr,addrlen)<0){ERR_MSG("bind");}puts("bind success");//接受对方地址信息struct sockaddr_in source_addr;socklen_t source_addrlen=sizeof(source_addr);char buf[128]="";while(1){//接收消息bzero(buf,sizeof(buf));int recv_res = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&source_addr, &source_addrlen);if(recv_res < 0){ERR_MSG("recvfrom");return -1;}printf("[%s:%d] : %s\n", \inet_ntoa(source_addr.sin_addr), ntohs(source_addr.sin_port), buf);}//关闭close(sfd);return 0;
}
发送端
代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>#define ERR_MSG(msg) do{\perror(msg);\fprintf(stderr,"__%d__",__LINE__);\
}while(0)
#define IP "192.168.125.2"
#define PORT 8888
#define GRP_IP "224.1.2.3"
/** function: 组播:发送方* @param [ in] * @param [out] * @return */
int main(int argc, const char *argv[])
{//创建报式套接字int sfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd<0){ERR_MSG("socket");return -1;}puts("socket success");//绑定IIF(P和端口号(广播ip)struct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(PORT);addr.sin_addr.s_addr=inet_addr(GRP_IP);socklen_t addrlen=sizeof(addr);if(bind(sfd,(struct sockaddr*)&addr,addrlen)<0){ERR_MSG("bind");}puts("bind success");char buf[128]="";while(1){//发送消息bzero(buf,sizeof(buf));printf("请输入>>> ");fgets(buf, sizeof(buf), stdin);buf[strlen(buf)-1] = 0;//发送数据, 主动发送给指定接收放,例如这里可以主动发给接收方if(sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, sizeof(addr)) < 0){ERR_MSG("sendto");return -1;}printf("sendto success\n");}//关闭close(sfd);return 0;
}
3.TCP并发
多进程
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
//自定义报错提示
#define ERR_MSG(msg) do{\fprintf(stderr,"__%d__",__LINE__);\perror(msg);\
}while(0)
#define SER_PORT 8888
#define SER_IP "192.168.125.2"
/** function: TCP服务端* @param [ in] * @param [out] * @return */int recv_send(int cfd,struct sockaddr_in cli_addr);
void handle(int sig){while(waitpid(-1,NULL,WNOHANG)>0);return ;
}int main(int argc, const char *argv[])
{//监听回收僵尸进程if(signal(SIGCHLD,handle)==SIG_ERR){ERR_MSG("signal");return -1;}//1.创建socket套接字,int sfd=socket(AF_INET,SOCK_STREAM,0);if(sfd<0){ERR_MSG("socket");return -1;}puts("socket create");//允许端口快速复用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0){ERR_MSG("setsockopt");return -1;}printf("允许端口快速复用成功\n");//2.绑定服务器IP和端口号bindstruct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(SER_PORT);addr.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(struct sockaddr*)&addr,sizeof(addr))<0){ERR_MSG("bind");return -1;}puts("bind success");//3.建立监听listenif(listen(sfd,128)<0){ERR_MSG("listen");return -1;}puts("listen suucess");//4.等待客户端连接, acceptstruct sockaddr_in cli_addr;socklen_t cli_addrlen=sizeof(cli_addr);pid_t pid;while(1){int cfd=accept(sfd,(struct sockaddr*)&cli_addr,&cli_addrlen);if(cfd<0){ERR_MSG("accept");return -1;}puts("accept");pid=fork();if(pid==0){//子进程执行信息收发recv_send(cfd,cli_addr);exit(0);}else if(pid<0){ERR_MSG("fork");return -1;}close(cfd);}//6.关闭close(sfd);return 0;
}
int recv_send(int cfd,struct sockaddr_in cli_addr){//5.接受发送消息recv;sendchar buf[128];while(1){bzero(buf,sizeof(buf));int recv_res=recv(cfd,buf,sizeof(buf),0);if(recv_res<0){ERR_MSG("recv");return -1;}else if(recv_res==0){printf("socket peer has shutdown\n");break;}puts("recv success");printf("[%s:%d]:%s\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),buf);if(strcmp(buf,"quit")==0)break;strcat(buf,"-----i has received");int send_res=send(cfd,buf,sizeof(buf),0);if(send_res<0){ERR_MSG("send");return -1;}puts("send success");}
}
多线程
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>//自定义报错提示
#define ERR_MSG(msg) do{\fprintf(stderr,"__%d__",__LINE__);\perror(msg);\
}while(0)
#define SER_PORT 8888
#define SER_IP "192.168.125.2"
struct cliMsg{int cfd;struct sockaddr_in cli_addr;
};
/** function: TCP服务端* @param [ in] * @param [out] * @return */
void* recv_send(void*arg);
int main(int argc, const char *argv[])
{//1.创建socket套接字,int sfd=socket(AF_INET,SOCK_STREAM,0);if(sfd<0){ERR_MSG("socket");return -1;}puts("socket create");//允许端口快速复用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0){ERR_MSG("setsockopt");return -1;}printf("允许端口快速复用成功\n");//2.绑定服务器IP和端口号bindstruct sockaddr_in addr;addr.sin_family=AF_INET;addr.sin_port=htons(SER_PORT);addr.sin_addr.s_addr=inet_addr(SER_IP);if(bind(sfd,(struct sockaddr*)&addr,sizeof(addr))<0){ERR_MSG("bind");return -1;}puts("bind success");//3.建立监听listenif(listen(sfd,128)<0){ERR_MSG("listen");return -1;}puts("listen suucess");//4.等待客户端连接, acceptstruct sockaddr_in cli_addr;socklen_t cli_addrlen=sizeof(cli_addr);pthread_t pth;while(1){int cfd=accept(sfd,(struct sockaddr*)&cli_addr,&cli_addrlen);if(cfd<0){ERR_MSG("accept");return -1;}puts("accept");struct cliMsg climsg;climsg.cfd=cfd;climsg.cli_addr=cli_addr;//创建调用线程执行if(pthread_create(&pth,NULL,recv_send,(void *)&climsg)!=0){fprintf(stderr,"pthread_create failed __%d__\n",__LINE__);return -1;}pthread_detach(pth);}close(sfd);return 0;
}
void* recv_send(void*arg){//5.接受发送消息recv;sendint cfd=((struct cliMsg*)arg)->cfd;struct sockaddr_in cli_addr=((struct cliMsg*)arg)->cli_addr;char buf[128];while(1){bzero(buf,sizeof(buf));int recv_res=recv(cfd,buf,sizeof(buf),0);if(recv_res<0){ERR_MSG("recv");break;}else if(recv_res==0){printf("socket peer has shutdown\n");break;}puts("recv success");printf("[%s:%d]:%s\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),buf);if(strcmp(buf,"quit")==0)break;strcat(buf,"-----i has received");int send_res=send(cfd,buf,sizeof(buf),0);if(send_res<0){ERR_MSG("send");break;}puts("send success");}close(cfd);pthread_exit(NULL);
}
今日思维导图
不知道最近确实是脑子比较慢,还是拖拉,做事太慢了,tcp的代码还没复敲;