客户端
服务端
1 #include<myhead.h>
2
3 #define SER_PORT 6666 //服务器端口
4 #define SER_IP "127.0.0.1" //服务器ip
5
6
7 int main(int argc, const char *argv[])
8 {
9 //创建套接字
10 int sfd=socket(AF_INET,SOCK_STREAM,0);
11 if(sfd==-1)
12 {
13 perror("socket error");
14 return -1;
15 }
16
17 //绑定 地址和端口号
18 struct sockaddr_in sin;
19 sin.sin_family=AF_INET;
20 sin.sin_port=htons(SER_PORT);
21 sin.sin_addr.s_addr=inet_addr(SER_IP);
22 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
23 {
24 perror("bind error");
25 return -1;
26 }
27
28
29 //定义用户套接字数组 个数
30 int client_arr[100]={0};
31 int client_count=0;
32
33 //开启监听
34 if(listen(sfd,128)==-1)
35 {
36 perror("listen error");
37 return -1;
38 }
39
40 //定义文件描述符集
41 fd_set readfds;
42 FD_ZERO(&readfds);
43
44
45 //添加
46 FD_SET(0,&readfds);
47 FD_SET(sfd,&readfds);
48
49 //最大的文件描述符
50 int maxfd=sfd;
51
52 //存储客户端地址信息结构体数组
53 struct sockaddr_in cin_arr[128];
54
55 int newfd=-1;
56
57 struct sockaddr_in cin; //接收客户端的信息
58 socklen_t addrlen =sizeof(cin); //用于接收长度
59
60 char wbuf[128]=""; // 信息搬运工
61 while(1)
62 {
63 fd_set temp =readfds;
64
65 //判断是否有文件描述符被激活
66 int res=select(FD_SETSIZE,&temp,0,0,0);
67 if(res==-1)
68 {
69 perror("select error");
70 return -1;
71 }
72
73 //当程序执行自此表示有文件描述符被激活
74 for(int i=0;i<=maxfd;i++) //遍历文件描述符
75 {
76 //查找是什么事件触发了文件描述符被激活
77 int res=FD_ISSET(i,&temp);
78 if(res==0)
79 {
80 continue;
81 }
82
83 //程序执行至此表示i是被触发事件的文件描述符
84 //判断sfd是否触发
85 if(i==sfd)
86 {
87 //接收连接请求
88 int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
89 if(newfd==-1)
90 {
91 perror("accept error");
92 return -1;
93 }
94 printf("成功连接到一个客户端\n");
95
96 //将新连接的客户端加入监视列表,下一次循环,碰到select就能监视到
97 FD_SET(newfd,&readfds);
98 //将客户端地址信息结构体放入客户端地址信息数组中
99 cin_arr[newfd]=cin;
100 //更新最大文件描述符
101 if(maxfd<newfd)
102 {
103 maxfd=newfd;
104 }
105 }
106 //判断是否是标准输入流触发该事件
107 else if(0==i)
108 {
109
110 fgets(wbuf,sizeof(wbuf),stdin); //从终端读取消息
111 wbuf[strlen(wbuf)-1]=0;
112 printf("发送的消息>>>%s\n",wbuf);
113
114 //将该消息发送给所有客户端
115 for(int i=4;i<=maxfd;i++)
116 {
117 if(send(i,wbuf,strlen(wbuf),0)==-1)
118 {
119 perror("send error");
120 return -1;
121 }
122 }
123 printf("发送成功\n");
124 }
125 else
126 {
127
128 char buf[128]="";
129
130 //清空容器
131 bzero(buf,sizeof(buf));
132 //从客户端套接字中读取数据
133 int res=recv(i,buf,sizeof(buf),0);
134 if(res==-1)
135 {
136 perror("recv error");
137 return -1;
138 }
139
140 else if(res==0)
141 {
142 printf("用户已经下线\n");
143 close(i);
144
145 FD_CLR(i,&readfds); //删除
146 //更新最大文件描述符
147 for(int j=maxfd;j>=sfd;j--)
148 {
149 if(FD_ISSET(j,&readfds))
150 {
151 maxfd =j;
152 break;
153 }
154 }
155 continue;
156 }
157 //正常收到客户端发来的消息
158 printf("[%s:%d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),buf);
159 }
160 }
161 }
162 //关闭
163 close(sfd);
164
165 return 0;
166 }
客户端
1 #include<myhead.h>
2 typedef struct sockaddr_in addr_in_t;
3 typedef struct sockaddr addr_t;
4 typedef struct sockaddr_un addr_un_t;
5 int main(int argc, const char *argv[])
6 {
7 if(argc!=2)
8 {
9 printf("请输入正确的端口号\n");
10 return -1;
11 }
12
13 int port = atoi(argv[1]);
14
15 //创建描述符
16 int client = socket(AF_INET,SOCK_STREAM,0);
17
18 //绑定连接服务器
19 addr_in_t addr;
20 addr.sin_family=AF_INET;
21 addr.sin_port=htons(port);
22 addr.sin_addr.s_addr=inet_addr("127.0.0.1");
23 if(connect(client,(addr_t*)&addr,sizeof(addr))==-1)
24 {
25 perror("connect error");
26 return -1;
27 }
28
29 fd_set readfds; //准备描述符集合
30 FD_ZERO(&readfds); //初始化
31
32 FD_SET(client,&readfds); //将客户端文件描述符加入描述符集合
33 FD_SET(0,&readfds); //将标准输入流添加入描述人集合
34
35
36 char buf[1024]="";
37 while(1)
38 {
39 //定义一个描述符集合
40 fd_set temp=readfds;
41 select(FD_SETSIZE,&temp,0,0,NULL); //阻塞
42
43 if(FD_ISSET(client,&temp))
44 {
45 //清空
46 bzero(buf,sizeof(buf));
47 recv(client,buf,sizeof(buf),0);
48 printf("接收消息:%s\n",buf);
49 }
50
51 if(FD_ISSET(0,&temp))
52 {
53 printf("请输入>>>");
54 scanf("%s",buf);
55 if(strcmp(buf,"q")==0)
56 {
57 break;
58 }
59
60 //发送数据
61 send(client,buf,strlen(buf),0);
62
63 }
64 }
65
66 return 0;
67 }
思维导图