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 //打印错误新的宏函数
14 #define ERR_MSG(msg) do{\
15 fprintf(stderr, " __%d__ ", __LINE__);\
16 perror(msg);\
17 }while(0)
18 #define PORT 8888 //1024~49151
19 #define IP "192.168.31.147" //本机IP,用ifconfig查看
20 //定义线程使用结构体
21 typedef struct
22 {
23 struct sockaddr_in sin;
24 int newfd;
25 }msg;
26 void *rcv(void *arg);//线程函数声明
27 void handler(int sig)
28 {
29 while(waitpid(-1,NULL,WNOHANG)<0);
30 }
31
32 int main(int argc, const char *argv[])
33 {
34 //用信号的方式回收僵尸进程
35 sighandler_t s = signal(SIGCHLD, handler);
36 if(SIG_ERR == s)
37 {
38 ERR_MSG("signal");
39 return -1;
40 }
41 //创建流式套接字
42 int sfd = socket(AF_INET, SOCK_STREAM, 0);
43 if(sfd < 0)
44 {
45 ERR_MSG("socket");
46 return -1;
47 }
48 printf("create socket success\n");
49 //允许端口快速重用
50 int reuse=1;
51 if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
52 {
53 ERR_MSG("setsockopt");
54 return -1;
55 }
56 //填充地址信息结构体,真实的地址信息结构体与协议族相关
57 //AF_INET,所以详情请看man 7 ip
58 struct sockaddr_in sin;
59 sin.sin_family = AF_INET;
60 sin.sin_port = htons(PORT); //网络字节序的端口号
61 sin.sin_addr.s_addr = inet_addr(IP); //网络字节序的IP地址
62
63 //将地址信息结构体绑定到套接字上
64 if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
65 {
66 ERR_MSG("bind");
67 return -1;
68 }
69 printf("bind success\n");
70
71 //将套接字设置为被动监听状态,让内核去监听是否有客户端连接;
72 if(listen(sfd, 10) < 0)
73 {
74 ERR_MSG("listen");
75 return -1;
76 }
77 printf("listen success\n");
78 int newfd;
79 pid_t pid;
80 pthread_t tid;
81 msg info;//定义结构体变量
82
83 struct sockaddr_in cin;
84 socklen_t addrlen = sizeof(cin);
85 while(1)
86 {
87 //从已完成连接的队列头中,取出一个客户端的信息,创建生成一个新的套接字文件描述符,
88 //该文件描述符才是与客户端通信的文件描述符!!!
89 newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);
90 if(newfd < 0)
91 {
92 perror("accept");
93 return -1;
94 }
95
96 //网络字节序的IP-->点分十进制 网络字节序的port--->本机字节序
97 printf("[%s : %d] newfd = %d\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port),newfd);
98 pid=fork();
99 if(pid<0)
100 {
101 ERR_MSG("fork");
102 return -1;
103 }
104 else if(pid==0)
105 {
106 close(sfd);
107 rcv(newfd,cin);
108 exit(0);
109 }
110 close(newfd);
111
112 }
113 close(sfd);
114 return 0;
115 }
116 //线程处理函数
117 int rcv(int newfd,struct sockaddr_in cin)
118 {
119 char buf[128] = "";
120 ssize_t res = 0;
121 while(1)
122 {
123 bzero(buf, sizeof(buf));
124 res = recv(newfd, buf, sizeof(buf), 0);
125 if(res < 0)
126 {
127 ERR_MSG("recv");
128 return -1;
129 }
130 else if(0 == res)
131 {
132 printf("[%s:%d] newfd = %d 客户端退出\n\n", inet_ntoa(cin.sin_addr),ntohs(cin.sin_port) ,newfd);
133 break;
134 }
135 printf("[%s:%d] fd=%d:%s\n", inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd, buf);
136 strcat(buf, "*_*");
137 if(send(newfd, buf, sizeof(buf), 0) < 0)
138 {
139 ERR_MSG("send");
140 return -1;
141 }
142 printf("发送成功\n");
143 }
144 close(newfd);
145 return 0;
146 }
~
~
~
~