1.广播模型
发送端
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/socket.h>
4 #include<arpa/inet.h>
5 #include<netinet/in.h>
6 #include<string.h>
7 #include<unistd.h>
8
9 #define SER_PORT 8888
10 #define SER_IP "192.168.124.255"
11
12 int main(int argc, const char *argv[])
13 {
14 //创建报式套接字
15 int cfd=socket(AF_INET,SOCK_DGRAM,0);
16 if(cfd<0)
17 {
18 fprintf(stderr,"line:%d ",__LINE__);
19 perror("socket");
20 return -1;
21 }
22 printf("创建报式套接字成功 cfd=%d __%d__\n",cfd,__LINE__);
23
24 //设置允许广播
25 int b=1;
26 if(setsockopt(cfd,SOL_SOCKET,SO_BROADCAST,&b,sizeof(b))<0)
27 {
28 fprintf(stderr,"line:%d ",__LINE__);
29 perror("setsockopt");
30 return -1;
31 }
32
33
34 //填充服务器的地址信息结构体,给sendto函数使用
35 //指定要将数据包发送给谁
36 //AF_INET--->MAN 7 ip
37 struct sockaddr_in sin;
38 sin.sin_family =AF_INET;//必须填AF_INET
39 sin.sin_port =htons(SER_PORT);//服务器绑定的端口号
40 sin.sin_addr.s_addr=inet_addr(SER_IP);//服务器绑定的IP
41
42 char buf[128]="";
43 struct sockaddr_in rcvaddr;
44 socklen_t addrlen=sizeof(rcvaddr);
45 while(1)
46 {
47 bzero(buf,sizeof(buf));
48 //发送
49 printf("请输入>>>");
50 fgets(buf,sizeof(buf),stdin);
51 buf[strlen(buf)-1]=0;
52 //将数据发送给接受方
53 if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))<0)
54 {
55 fprintf(stderr,"line:%d ",__LINE__);
56 perror("sendto");
57 return -1;
58 }
59 printf("发送成功\n");
60
61 }
62 //关闭
63 close(cfd);
64 return 0;
65 }
66
接收端
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/socket.h>
4 #include<arpa/inet.h>
5 #include<netinet/in.h>
6 #include<string.h>
7 #include<unistd.h>
8
9 #define PORT 8888
10 #define IP "192.168.124.255"
11
12 int main(int argc, const char *argv[])
13 {
14 //创建报式套接字
15 int sfd=socket(AF_INET,SOCK_DGRAM,0);
16 if(sfd<0)
17 {
18 fprintf(stderr,"line:%d ",__LINE__);
19 perror("socket");
20 return -1;
21 }
22 printf("创建报式套接字成功 sfd=%d __%d__\n",sfd,__LINE__);
23
24 //允许端口号被快速重复使用
25 int reuse = 1;
26 if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
27 {
28 fprintf(stderr, "line:%d ", __LINE__);
29 perror("setsockopt");
30 return -1;
31 }
32
33 //填充服务器的地址信息结构体,真实的地址信息结构体根据地址族制定
34 //AF_INET--->MAN 7 ip
35 struct sockaddr_in sin;
36 sin.sin_family =AF_INET;//必须填AF_INET
37 sin.sin_port =htons(PORT);//端口号的网络字节序 1024~49151
38 sin.sin_addr.s_addr=inet_addr(IP);//服务器要运行的主机的IP的网络地址
39 //ifconfig查找本机的IP地址
40 //绑定服务器自身的地址信息-->必须绑定
41 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
42 {
43 fprintf(stderr,"line:%d ",__LINE__);
44 perror("bind");
45 return -1;
46 }
47 printf("bind success __%d__\n",__LINE__);
48
49 char buf[128]="";
50 struct sockaddr_in cin;
51 socklen_t addrlen=sizeof(cin);
52 while(1)
53 {
54 bzero(buf,sizeof(buf));
55 //接收
56 //if(recvfrom(sfd,buf,sizeof(buf),0,NULL,NULL)<0)
57 //if(recv(sfd,buf,sizeof(buf),0)<0)
58 //if(read(sfd,buf,sizeof(buf))<0)
59 if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen)<0)
60 {
61 fprintf(stderr,"line:%d ",__LINE__);
62 perror("recvfrom");
63 return -1;
64 }
65 printf(":%s __%d__\n",buf,__LINE__);
66 }
67 close(sfd);
68
69
70 return 0;
71 }
2.组播模型
发送端
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/socket.h>
4 #include<arpa/inet.h>
5 #include<netinet/in.h>
6 #include<string.h>
7 #include<unistd.h>
8
9 #define SER_PORT 8888
10 #define GRP_IP "224.1.2.3"
11
12 int main(int argc, const char *argv[])
13 {
14 //创建报式套接字
15 int cfd=socket(AF_INET,SOCK_DGRAM,0);
16 if(cfd<0)
17 {
18 fprintf(stderr,"line:%d ",__LINE__);
19 perror("socket");
20 return -1;
21 }
22 printf("创建报式套接字成功 cfd=%d __%d__\n",cfd,__LINE__);
23
24 //填充接收方的地址信息结构体,给sendto函数使用
25 //指定要将数据包发送给谁
26 //AF_INET--->MAN 7 ip
27 struct sockaddr_in sin;
28 sin.sin_family =AF_INET;//必须填AF_INET
29 sin.sin_port =htons(SER_PORT);//服务器绑定的端口号
30 sin.sin_addr.s_addr=inet_addr(GRP_IP);//服务器绑定的IP
31
32 char buf[128]="";
33 struct sockaddr_in rcvaddr;
34 socklen_t addrlen=sizeof(rcvaddr);
35 while(1)
36 {
37 bzero(buf,sizeof(buf));
38 //发送
39 printf("请输入>>>");
40 fgets(buf,sizeof(buf),stdin);
41 buf[strlen(buf)-1]=0;
42 //将数据发送给接受方
43 if(sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))<0)
44 {
45 fprintf(stderr,"line:%d ",__LINE__);
46 perror("sendto");
47 return -1;
48 }
49 printf("发送成功\n");
50
51 }
52 //关闭
53 close(cfd);
54 return 0;
55 }
56
接收端
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/socket.h>
4 #include<arpa/inet.h>
5 #include<netinet/in.h>
6 #include<string.h>
7 #include<unistd.h>
8
9 #define PORT 8888
10 #define IP "192.168.124.93"
11 #define GRP_IP "224.1.2.3"
12
13 int main(int argc, const char *argv[])
14 {
15 //创建报式套接字
16 int sfd=socket(AF_INET,SOCK_DGRAM,0);
17 if(sfd<0)
18 {
19 fprintf(stderr,"line:%d ",__LINE__);
20 perror("socket");
21 return -1;
22 }
23 printf("创建报式套接字成功 sfd=%d __%d__\n",sfd,__LINE__);
24
25 //加入多播组
26 struct ip_mreqn mq;
27 mq.imr_multiaddr.s_addr =inet_addr(GRP_IP);
28 mq.imr_address.s_addr =inet_addr(IP);
29 mq.imr_ifindex =0;
30 if(setsockopt(sfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mq,sizeof(mq))<0)
31 {
32 fprintf(stderr,"line:%d ",__LINE__);
33 perror("setsockopt");
34 return -1;
35 }
36 printf("加入小组[%s]成功\n",GRP_IP);
37 //允许端口号被快速重复使用
38 int reuse = 1;
39 if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
40
41 {
42 fprintf(stderr, "line:%d ", __LINE__);
43 perror("setsockopt");
44 return -1;
45 }
46
47 //填充接收方的地址信息结构体,真实的地址信息结构体根据地址族制定
48 //AF_INET--->MAN 7 ip
49 struct sockaddr_in sin;
50 sin.sin_family =AF_INET;//必须填AF_INET
51 sin.sin_port =htons(PORT);//端口号的网络字节序 1024~49151
52 sin.sin_addr.s_addr=inet_addr(GRP_IP);//接收方加入的组播IP
53
54 //ifconfig查找本机的IP地址
55 //绑定接收方自身的地址信息-->必须绑定
56 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
57 {
58 fprintf(stderr,"line:%d ",__LINE__);
59 perror("bind");
60 return -1;
61 }
62 printf("bind success __%d__\n",__LINE__);
63
64 char buf[128]="";
65 struct sockaddr_in cin;
66 socklen_t addrlen=sizeof(cin);
67 while(1)
68 {
69 bzero(buf,sizeof(buf));
70 //接收
71 //if(recvfrom(sfd,buf,sizeof(buf),0,NULL,NULL)<0)
72 //if(recv(sfd,buf,sizeof(buf),0)<0)
73 //if(read(sfd,buf,sizeof(buf))<0)
74 if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen)<0)
75 {
76 fprintf(stderr,"line:%d ",__LINE__);
77 perror("recvfrom");
78 return -1;
79 }
80 printf(":%s __%d__\n",buf,__LINE__);
81 }
82 close(sfd);
83
84
85 return 0;
86 }
3.TCP进程并发模型
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/socket.h>
4 #include<arpa/inet.h>
5 #include<netinet/in.h>
6 #include<string.h>
7 #include<unistd.h>
8 #include<stdlib.h>
9 #include<sys/wait.h>
10 #include<signal.h>
11
12 #define PORT 8888
13 #define IP "192.168.124.93"
14
15 int do_cli_msg(int newfd,struct sockaddr_in cin);
16
17 void recycle_zombie(int sig)
18 {
19 while(waitpid(-1,NULL,WNOHANG)>0);
20 return;
21 }
22
23 int main(int argc, const char *argv[])
24 {
25 //捕获17)SIGCHLD信号
26 if(signal(SIGCHLD,recycle_zombie)==SIG_ERR)
27 {
28 perror("signal");
29 return -1;
30 }
31 //创建流式套接字文件
32 int sfd=socket(AF_INET,SOCK_STREAM,0);
33 if(sfd<0)
34 {
35 fprintf(stderr,"line:%d \n",__LINE__);
36 perror("socket");
37 return -1;
38 }
39 printf("创建流式套接字成功 sfd=%d __%d__\n",sfd,__LINE__);
40
41 //允许端口号被快速重复使用
42 int reuse = 1;
43 if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
44 {
45 fprintf(stderr, "line:%d ", __LINE__);
46 perror("setsockopt");
47 return -1;
48 }
49
50 //填充服务器的地址信息结构体,真实的地址信息结构体根据地址族制定
51 //AF_INET--->man 7 ip
52 struct sockaddr_in sin;
53 sin.sin_family =AF_INET; //必须填AF_INET
54 sin.sin_port =htons(PORT);//端口号的网络字节序1024~49151
55 sin.sin_addr.s_addr =inet_addr(IP);//服务器要运行的主机的IP的网络地址
56 //ifconfig查找本机的IP地址
57 //绑定服务器自身的地址信息-->必修绑定
58 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
59 {
60 fprintf(stderr,"line:%d ",__LINE__);
61 perror("bind");
62 return -1;
63 }
64 printf("bind success __%d__\n",__LINE__);
65
66 //将套接字设置为被动监听状态
67 if(listen(sfd,128)<0)
68 {
69 fprintf(stderr,"line:%d ",__LINE__);
70 perror("listen");
71 return -1;
72 }
73 printf("listen success __%d__\n",__LINE__);
74
75 struct sockaddr_in cin; //存储客户端信息的
76 socklen_t addrlen=sizeof(cin);
77 int newfd;
78 pid_t pid=0;
79
80 while(1)
81 {
82 //父进程只负责连接(accept)
83 //会从已完成连接队列的对头获取一个客户端的信息,生成一个新的文件描述符
84 //accept(sfd,NULL,NULL);
85 newfd= accept(sfd,(struct sockaddr*)&cin,&addrlen);
86 if(newfd<0)
87 {
88 fprintf(stderr,"line:%d ",__LINE__);
89 perror("accept");
90 return -1;
91 }
92 printf("[%s:%d] 客户端连接成功 newfd=%d __%d__\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,__LINE__);
93
94 //能运行到当前位置,则代表有客户端连接成功
95 //此时需要创建一个新的进程,专门用于与客户端进行通信--->子进程只负责收发
96 pid = fork();
97 if(0==pid)
98 {
99 close(sfd); //sfd用于监听客户端连接,对于子进程没有用
100 do_cli_msg(newfd,cin);
101 close(newfd); //执行完交互后,newfd没有用了,需要关闭
102 exit(0);//子进程只负责收发,所以任务结束后,一定要退出子进程
103 }
104 else if(pid>0)
105 {
106 close(newfd);
107 }
108 else
109 {
110 fprintf(stderr,"line:%d ",__LINE__);
111 perror("fork");
112 return -1;
113 }
114 }
115 //关闭文件描述符
116 close(sfd);
117 return 0;
118 }
119
120
121 //子进程中用于处理于客户端交互的功能代码
122 int do_cli_msg(int newfd,struct sockaddr_in cin)
123 {
124 char buf[128];
125 ssize_t res;
126 while(1)
127 {
128 bzero(buf,sizeof(buf));
129 //接收
130 res=recv(newfd,buf,sizeof(buf),0);
131 if(res<0)
132 {
133 fprintf(stderr,"line:%d ",__LINE__);
134 perror("recv");
135 return -1;
136 }
137 else if(0==res)
138 {
139 printf("[%s:%d] 客户端下线 newfd=%d __%d__\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,__LINE__);
140 break;
141 }
142 printf("[%s:%d] newfd=%d %s __%d__\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,buf,__LINE__);
143
144 //发送
145 strcat(buf,"*_*");
146 if(send(newfd,buf,sizeof(buf),0)<0)
147 {
148 fprintf(stderr,"line:%d ",__LINE__);
149 perror("send");
150 return -1;
151 }
152 printf("send success __%d__\n",__LINE__);
153 }
154 return 0;
155 }
4.TCP线程并发模型
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/socket.h>
4 #include<arpa/inet.h>
5 #include<netinet/in.h>
6 #include<string.h>
7 #include<unistd.h>
8 #include<stdlib.h>
9 #include<sys/wait.h>
10 #include<signal.h>
11 #include<pthread.h>
12
13 #define PORT 8888
14 #define IP "192.168.124.93"
15
16 //传入到分支线程回调函数的参数类型
17 struct CliInfo
18 {
19 int newfd;
20 struct sockaddr_in cin;
21 };
22 void* do_cli_msg(void* arg);
23
24 int main(int argc, const char *argv[])
25 {
26 //创建流式套接字文件
27 int sfd=socket(AF_INET,SOCK_STREAM,0);
28 if(sfd<0)
29 {
30 fprintf(stderr,"line:%d \n",__LINE__);
31 perror("socket");
32 return -1;
33 }
34 printf("创建流式套接字成功 sfd=%d __%d__\n",sfd,__LINE__);
35
36 //允许端口号被快速重复使用
37 int reuse = 1;
38 if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
39 {
40 fprintf(stderr, "line:%d ", __LINE__);
41 perror("setsockopt");
42 return -1;
43 }
44
45 //填充服务器的地址信息结构体,真实的地址信息结构体根据地址族制定
46 //AF_INET--->man 7 ip
47 struct sockaddr_in sin;
48 sin.sin_family =AF_INET; //必须填AF_INET
49 sin.sin_port =htons(PORT);//端口号的网络字节序1024~49151
50 sin.sin_addr.s_addr =inet_addr(IP);//服务器要运行的主机的IP的网络地址
51 //ifconfig查找本机的IP地址
52 //绑定服务器自身的地址信息-->必修绑定
53 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
54 {
55 fprintf(stderr,"line:%d ",__LINE__);
56 perror("bind");
57 return -1;
58 }
59 printf("bind success __%d__\n",__LINE__);
60
61 //将套接字设置为被动监听状态
62 if(listen(sfd,128)<0)
63 {
64 fprintf(stderr,"line:%d ",__LINE__);
65 perror("listen");
66 return -1;
67 }
68 printf("listen success __%d__\n",__LINE__);
69
70 struct sockaddr_in cin; //存储客户端信息的
71 socklen_t addrlen=sizeof(cin);
72 int newfd;
73 pthread_t tid;
74 struct CliInfo dcli;
75
76 while(1)
77 {
78 //主线程只负责连接(accept)
79 //会从已完成连接队列的对头获取一个客户端的信息,生成一个新的文件描述符
80 //当代码阻塞在accept函数的位置时,会遍历文件文件描述符找到最小的没有被使用的文件描述符,并占用
81 //accept(sfd,NULL,NULL);
82 newfd= accept(sfd,(struct sockaddr*)&cin,&addrlen);
83 if(newfd<0)
84 {
85 fprintf(stderr,"line:%d ",__LINE__);
86 perror("accept");
87 return -1;
88 }
89 printf("[%s:%d] 客户端连接成功 newfd=%d __%d__\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,__LINE__);
90
91 //能运行到当前位置,则代表有客户端连接成功,此时需要创建一个分支线程负责交互
92 //分支线程只负责交互
93 dcli.newfd=newfd;
94 dcli.cin=cin;
95 if(pthread_create(&tid,NULL,do_cli_msg,(void*)&dcli)!=0)
96 {
97 fprintf(stderr,"line:%d pthread_create failed\n",__LINE__);
98 return -1;
99 }
100 pthread_detach(tid); //分离线程,tid线程退出后资源自动被回收
101 }
102 //关闭文件描述符
103 close(sfd);
104 return 0;
105 }
106
107 //分支线程的回调函数
108 void* do_cli_msg(void* arg) //void* arg=(void*)&dcli
109 {
110 int newfd=((struct CliInfo*)arg)->newfd;
111 struct sockaddr_in cin=((struct CliInfo*)arg)->cin;
112 char buf[128];
113 ssize_t res;
114 while(1)
115 {
116 bzero(buf,sizeof(buf));
117 //接收
118 res=recv(newfd,buf,sizeof(buf),0);
119 if(res<0)
120 {
121 fprintf(stderr,"line:%d ",__LINE__);
122 perror("recv");
123 break;
124 }
125 else if(0==res)
126 {
127 printf("[%s:%d] 客户端下线 newfd=%d __%d__\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,__LINE__);
128 break;
129 }
130 printf("[%s:%d] newfd=%d %s __%d__\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,buf,__LINE__);
131
132 //发送
133 strcat(buf,"*_*");
134 if(send(newfd,buf,sizeof(buf),0)<0)
135 {
136 fprintf(stderr,"line:%d ",__LINE__);
137 perror("send");
138 break;
139 }
140 printf("send success __%d__\n",__LINE__);
141 }
142 close(newfd);
143 pthread_exit(NULL);
144 }