#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 int main(int argc, const char *argv[])
28 {
29 //创建流式套接字
30 int sfd = socket(AF_INET, SOCK_STREAM, 0);
31 if(sfd < 0)
32 {
33 ERR_MSG("socket");
34 return -1;
35 }
36 printf("create socket success\n");
37 //允许端口快速重用
38 int reuse=1;
39 if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
40 {
41 ERR_MSG("setsockopt");
42 return -1;
43 }
44 //填充地址信息结构体,真实的地址信息结构体与协议族相关
45 //AF_INET,所以详情请看man 7 ip
46 struct sockaddr_in sin;
47 sin.sin_family = AF_INET;
48 sin.sin_port = htons(PORT); //网络字节序的端口号
49 sin.sin_addr.s_addr = inet_addr(IP); //网络字节序的IP地址
50
51 //将地址信息结构体绑定到套接字上
52 if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
53 {
54 ERR_MSG("bind");
55 return -1;
56 }
57 printf("bind success\n");
58
59 //将套接字设置为被动监听状态,让内核去监听是否有客户端连接;
60 if(listen(sfd, 10) < 0)
61 {
62 ERR_MSG("listen");
63 return -1;
64 }
65 printf("listen success\n");
66 int newfd;
67 pthread_t tid;
68 msg info;//定义结构体变量
69
70 struct sockaddr_in cin;
71 socklen_t addrlen = sizeof(cin);
72 while(1)
73 {
74 //从已完成连接的队列头中,取出一个客户端的信息,创建生成一个新的套接字文件描述符,
75 //该文件描述符才是与客户端通信的文件描述符!!!
76 newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);
77 if(newfd < 0)
78 {
79 perror("accept");
80 return -1;
81 }
82
83 //网络字节序的IP-->点分十进制 网络字节序的port--->本机字节序
84 printf("[%s : %d] newfd = %d\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port),newfd);
85 info.newfd=newfd;
86 info.sin=cin;
87 if(pthread_create(&tid,NULL,rcv,(void*)&info)!=0)
88 {
89 ERR_MSG("pthread_create");
90 return -1;
91 }
92 }
93
94
95 close(sfd);
96 return 0;
97 }
98 //线程处理函数
99 void *rcv(void *arg)
100 {
101 pthread_detach(pthread_self());//自己分离自己,因为pthread_join会有阻塞所以不用
102 char buf[128] = "";
103 int newfd=(*(msg*)arg).newfd;
104 //struct sockaddr_in cin=(*(msg*)arg).sin;
105
106 ssize_t res = 0;
107 while(1)
108 {
109 bzero(buf, sizeof(buf));
110 //循环接收
111 res = recv((*(msg*)arg).newfd, buf, sizeof(buf), 0);
112 if(res < 0)
113 {
114 ERR_MSG("recv");
115 }
116 else if(0 == res)
117 {
118 printf("[%s : %d] newfd = %d客户端退出\n", inet_ntoa((*(msg*)arg).sin.sin_addr), ntohs((*(msg*)arg).sin.sin_port),(*(msg*)arg).newfd);
119 break;
120 }
121 //发送数据
122 strcat(buf,"*_*");
123 if(send((*(msg*)arg).newfd,buf,sizeof(buf),0)<0)
124 {
125 ERR_MSG("send");
126 }
127 printf("[%s : %d] newfd = %d : %s\n", inet_ntoa((*(msg*)arg).sin.sin_addr), ntohs((*(msg*)arg).sin.sin_port),(*(msg*)arg).newfd, buf);
128 }
129 close((*(msg*)arg).newfd);
130 pthread_exit(NULL);
131 return 0;
132
133 }
134