服务器端:server.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <arpa/inet.h>
6 #include <pthread.h>
7 void* working(void *arg);
8 //信息结构体
9 struct sockinfo
10 {
11 struct sockaddr_in addr;//用来存储地址信息
12 int fd;//用来存储文件描述符
13 };
14 //创建一个信息数组,即同时支持与512个客户端进行通信,若想让其无上限,需要维护一个链表
15 //在C++中可以维护一个STL
16 struct sockinfo infos[512];
17 int main()
18 {
19 //创建监听的套接字
20 int lfd=socket(AF_INET,SOCK_STREAM,0);
21 if(lfd==-1)
22 {
23 perror("socket");
24 return -1;
25 }
26 struct sockaddr_in addr;
27 addr.sin_family=AF_INET;
28 addr.sin_port=htons(999); //主机字节序转换为网络字节序,即小端字节序转换成为大端字节序
29 addr.sin_addr.s_addr=INADDR_ANY;
30 int ret=bind(lfd,(struct sockaddr*)&addr,sizeof(addr));
31 if(ret==-1)
32 {
33 perror("bind");
34 return -1;
35 }
36 //设置监听
37 ret=listen(lfd,128);//设置最大监听数量为128个
38 if(ret==-1)
39 {
40 perror("listen");
41 return -1;
42 }
43
44 //初始化结构数组
45 int max=sizeof(infos)/sizeof(infos[0]);//计算数组的大小
46 //将结构体数组中每个元素初始化为0
47 int i=0;
48 for(i=0;i<max;++i)
49 {
50 bzero(&infos[i],sizeof(infos[i]));
51 //memset(infos,0,sizeof(infos));
52 //将结构体中的文件描述符修改为-1
53 infos[i].fd=-1;//通过文件描述符的值是否为-1来判断当前数组元素是否是被占用的
54
55 }
56
57 //阻塞并等待客户端的连接
58 int clilen=sizeof(struct sockaddr_in);
59 while(1)
60 {
61 struct sockinfo* pinfo;
62 int i=0;
63 for(i=0;i<max;++i)
64 {
65 if(infos[i].fd==-1)//此时说明该元素是可以使用的
66 {
67 pinfo=&infos[i];
68 break;
69 }
70 }
71 int cfd=accept(lfd, (struct sockaddr*)&pinfo->addr,&clilen);
72 pinfo->fd=cfd;//保存返回的文件描述符
73 if(cfd==-1)
74 {
75 perror("accept");
76 break;
77 }
78 //与客户端建立连接后,需要与客户端进行通信。与客户端的通信需要一个子线程来连接
79 //创建子线程
80 pthread_t tid;
81 pthread_create(&tid,NULL,working,pinfo);//pinfo就是需要传递给working函数的参数
82 //任务执行完毕之后,子线程需要退出。此时,需要由主线程来释放子线程的资源
83 //此时,需要调用detach()函数来使主线程与子线程进行资源分离
84 pthread_detach(tid);
85 }
86 close(lfd);
87 return 0;
88 }
89
90 //子线程的任务函数·
91 void* working(void *arg)
92 {
93 struct sockinfo* pinfo=(struct sockinfo*)arg;
94 //打印客户端地址
95 char ip[1024]={0};
96 printf("客户端IP地址:%s,端口:%d\n",inet_ntop(AF_INET,&pinfo->addr.sin_addr.s_addr,ip,sizeof(ip)),ntohs(pinfo->addr.sin_port));
97 //和客户建立通信
98 while(1)
99 {
100 char buf[1024];
101 memset(buf,0,sizeof(buf));
102 int len=read(pinfo->fd,buf,sizeof(buf));
103 if(len>0)
104 {
105 printf("客户端say:%s\n",buf);
106 write(pinfo->fd,buf,len);
107 }
108 else if(len==0)
109 {
110 printf("客户端断开了连接...\n");
111 break;
112 }
113 else
114 {
115 perror("read");
116 break;
117 }
118 }
119 close(pinfo->fd);
120 pinfo->fd=-1;//将通信描述符再次初始化为-1
121 return NULL;
122 }
客户端:client.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <arpa/inet.h>
6 int main()
7 {
8 //创建监听的套接字
9 int fd=socket(AF_INET,SOCK_STREAM,0);
10 if(fd==-1)
11 {
12 perror("socket");
13 exit(0);
14 }
15 struct sockaddr_in addr;
16 addr.sin_family=AF_INET;
17 addr.sin_port=htons(999); //主机字节序转换为网络字节序,即小端字节序转换成为大端字节序
18 inet_pton(AF_INET,"192.168.64.134",&addr.sin_addr.s_addr);
19 int ret=connect(fd,(struct sockaddr*)&addr,sizeof(addr));
20 if(ret==-1)
21 {
22 perror("connetc");
23 exit(0);
24 }
25 //和服务器通信
26 int number=0;
27 while(1)
28 { //发送数据
29 char buf[1024];
30 sprintf(buf,"你好,服务器...%d\n",number++);
31 write(fd,buf,strlen(buf)+1);
32 //接收数据
33 memset(buf,0,sizeof(buf));
34 int len=read(fd,buf,sizeof(buf));
35 if(len>0)
36 {
37 printf("服务器say:%s\n",buf);
38 write(fd,buf,len);
39 }
40 else if(len==0)
41 {
42 printf("服务器断开了连接...\n");
43 break;
44 }
45 else
46 {
47 perror("read");
48 break;
49 }
50 sleep(1);
51 }
52 close(fd);
53 return 0;
54 }
编译:gcc server.c -lpthread -o server
gcc client.c -lpthread -o client
启动运行:
先运行服务器端./server,再运行客户端./client