(OK) server-client-pthread-c language
server.c
client.c
点击(此处)折叠或打开
- // gcc
-lpthread server.c
-o server
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
- #include <pthread.h>
- //#endif
- #define BUF_SIZE 1024 //默认缓冲区
- #define SERVER_PORT 11111 //监听端口
- #define SERVER_HOST "127.0.0.1" //服务器IP地址
- #define EPOLL_RUN_TIMEOUT -1 //epoll的超时时间
- #define EPOLL_SIZE 10000 //epoll监听的客户端的最大数目
- #define LISTEN_SIZE 10 //监听队列长度
- #define STR_WELCOME "Welcome to seChat! You ID is : Client #%d"
- #define STR_MESSAGE "Client #%d>> %s"
- #define STR_NOONE_CONNECTED "Noone connected to server expect you!"
- #define CMD_EXIT "EXIT"
- //两个有用的宏定义:检查和赋值并且检测
- #define CHK(eval)
if(eval
< 0){perror("eval");
exit(-1);}
- #define CHK2(res, eval)
if((res
= eval)
< 0){perror("eval");
exit(-1);}
- void* handle_message(void
*arg);
- int main(int argc, char
*argv[])
- {
- int listener; //监听socket
- struct sockaddr_in addr, peer;
- addr.sin_family
= PF_INET;
- addr.sin_port
= htons(SERVER_PORT);
- addr.sin_addr.s_addr
= inet_addr(SERVER_HOST);
- socklen_t socklen;
- socklen = sizeof(struct sockaddr_in);
- int client;
- CHK2(listener, socket(PF_INET, SOCK_STREAM, 0)); //初始化监听socket
- // 设置套接字选项避免地址使用错误
- int on=1;
- if((setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)
- {
- perror("setsockopt failed");
- exit(EXIT_FAILURE);
- }
- CHK(bind(listener,
(struct sockaddr *)&addr, sizeof(addr))); //绑定监听socket
- //printf("listen\n");
- CHK(listen(listener, LISTEN_SIZE)); //设置监听
- printf("listening\n");
- while (1)
{
- //printf("accept\n");
- CHK2(client, accept(listener,
(struct sockaddr *)&peer,
&socklen));
- printf("accepted\n");
- pthread_t reader;
- int rt
= pthread_create(&reader,
NULL, handle_message,
(void *)&client);
- if (-1
== rt)
{
- printf("thread creation error\n");
- return -1;
- }
- }
- }
- void* handle_message(void
*arg)
- {
- int client
= *((int*)arg);
- //sleep(5);
- char buf[BUF_SIZE];
- int len;
- while(1){
- bzero(buf, BUF_SIZE);
- CHK2(len, recv(client, buf, BUF_SIZE,
0)); //接受客户端信息
- if (len
== 0) //客户端关闭或出错,关闭socket,并从list移除socket
- {
- printf("close-client: %d\n", client);
- CHK(close(client));
- return NULL;
- } else //向客户端发送信息
- {
- CHK(send(client, STR_NOONE_CONNECTED, strlen(STR_NOONE_CONNECTED),
0));
- printf("receive: %s from %d\n", buf, client);
- }
- }
- //return
len;
- //return
NULL;
- }
点击(此处)折叠或打开
- // gcc client.c
-o client
- // gcc
-lpthread client.c
-o client
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
- #include <sys/epoll.h>
- //#endif
- #define BUF_SIZE 1024 //默认缓冲区
- #define SERVER_PORT 11111 //监听端口
- #define SERVER_HOST "127.0.0.1" //服务器IP地址
- #define EPOLL_RUN_TIMEOUT -1 //epoll的超时时间
- #define EPOLL_SIZE 10000 //epoll监听的客户端的最大数目
- #define STR_WELCOME "Welcome to seChat! You ID is : Client #%d"
- #define STR_MESSAGE "Client #%d>> %s"
- #define STR_NOONE_CONNECTED "Noone connected to server expect you!"
- #define CMD_EXIT "EXIT"
- //两个有用的宏定义:检查和赋值并且检测
- #define CHK(eval)
if(eval
< 0){perror("eval");
exit(-1);}
- #define CHK2(res, eval)
if((res
= eval)
< 0){perror("eval");
exit(-1);}
- char message[BUF_SIZE];
- /*
- 流程:
- 调用fork产生两个进程,两个进程通过管道进行通信
- 子进程:等待客户输入,并将客户输入的信息通过管道写给父进程
- 父进程:接受服务器的信息并显示,将从子进程接受到的信息发送给服务器
- */
- int main(int argc, char
*argv[])
- {
- int sock, pid, pipe_fd[2], epfd;
- struct sockaddr_in addr;
- addr.sin_family
= PF_INET;
- addr.sin_port
= htons(SERVER_PORT);
- addr.sin_addr.s_addr
= inet_addr(SERVER_HOST);
- static struct epoll_event ev, events[2];
- ev.events
= EPOLLIN | EPOLLET;
- //退出标志
- int continue_to_work
= 1;
- CHK2(sock, socket(PF_INET, SOCK_STREAM, 0));
- CHK(connect(sock,
(struct sockaddr *)&addr, sizeof(addr))
< 0);
- CHK(pipe(pipe_fd));
- CHK2(epfd, epoll_create(EPOLL_SIZE));
- ev.data.fd
= sock;
- CHK(epoll_ctl(epfd, EPOLL_CTL_ADD, sock,
&ev));
- ev.data.fd
= pipe_fd[0];
- CHK(epoll_ctl(epfd, EPOLL_CTL_ADD, pipe_fd[0],
&ev));
- // 调用fork产生两个进程
- CHK2(pid, fork());
- switch (pid)
{
- case 0: // 子进程
- close(pipe_fd[0]); //
关闭读端
- printf("Enter 'exit' to exit\n");
- while
(continue_to_work)
{
- bzero(&message, BUF_SIZE);
- fgets(message, BUF_SIZE, stdin);
- // 当收到exit命令时,退出
- if
(strncasecmp(message, CMD_EXIT, strlen(CMD_EXIT))
== 0)
{
- continue_to_work = 0;
- }
else {
- CHK(write(pipe_fd[1], message,
strlen(message)
- 1));
- }
- }
- break;
- default: // 父进程
- close(pipe_fd[1]); //
关闭写端
- int epoll_events_count, res;
- while
(continue_to_work)
{
- CHK2(epoll_events_count, epoll_wait(epfd, events, 2,
EPOLL_RUN_TIMEOUT));
- for
(int i = 0; i
< epoll_events_count; i++)
{
- bzero(&message, BUF_SIZE);
- if
(events[i].data.fd
== sock) //从服务器接受信息
- {
- CHK2(res, recv(sock, message, BUF_SIZE,
0));
- if
(res == 0) //服务器已关闭
- {
- CHK(close(sock));
- continue_to_work = 0;
- }
else {
- printf("%s\n", message);
- }
- }
else //从子进程接受信息
- {
- CHK2(res, read(events[i].data.fd,
message, BUF_SIZE));
- if
(res == 0)
{
- continue_to_work = 0;
- }
else {
- CHK(send(sock, message, BUF_SIZE, 0));
- }
- }
- }
- }
- }
- if (pid)
{
- close(pipe_fd[0]);
- close(sock);
- } else
{
- close(pipe_fd[1]);
- }
- return 0;
- }