server.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;
-
}
client.c
-
// 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;
-
}
阅读(776) | 评论(0) | 转发(0) |