Created
January 27, 2018 10:28
-
-
Save corvofeng/124b44334f831020ce1eade28cd7a650 to your computer and use it in GitHub Desktop.
Client-Server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 编译: | |
* gcc client.c -o client | |
* | |
* 运行: | |
* ./client 127.0.0.1 12345 <string> | |
*/ | |
#include "stdio.h" | |
#include "sys/socket.h" | |
#include "arpa/inet.h" | |
#include "stdlib.h" | |
#include "string.h" | |
#include "unistd.h" | |
#define BUFFSIZE 1024 | |
void Die(char *mess) { | |
perror(mess); | |
exit(1); | |
} | |
int main(int argc, char const *argv[]) | |
{ | |
int sock; | |
struct sockaddr_in echoserver; | |
char buff[BUFFSIZE]; | |
unsigned int echolen; | |
int recvived = 0; | |
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) | |
{ | |
Die("Failed to create socket"); | |
} | |
memset(&echoserver, 0, sizeof(echoserver)); | |
echoserver.sin_family = AF_INET; | |
echoserver.sin_addr.s_addr = inet_addr(argv[1]); | |
echoserver.sin_port = htons(atoi(argv[2])); | |
if (connect(sock, (struct sockaddr *)&echoserver, sizeof(echoserver)) < 0) | |
{ | |
Die("Failed to connect with server"); | |
} | |
echolen = strlen(argv[3]); | |
if (send(sock, argv[3], echolen, 0) != echolen) | |
{ | |
Die("Mismatch in number of sent bytes"); | |
} | |
// char s[] = " if it could be recvived"; | |
fprintf(stdout, "Received;\n"); | |
while(recvived < echolen) { | |
scanf("%s", buff); | |
fflush(stdin); | |
if (send(sock, buff, strlen(buff), 0) != strlen(buff)) { | |
Die("Mismatch in number of sent bytes"); | |
} | |
/* | |
int bytes = 0; | |
if (bytes = recv(sock, buff, BUFFSIZE - 1, 0) < 1) { | |
printf("%d\n", bytes); | |
Die("Failed to recvive bytes from server"); | |
} | |
recvived += bytes; | |
buff[bytes] = '\0'; | |
fprintf(stdout, buff); | |
*/ | |
} | |
fprintf(stdout, "\n"); | |
close(sock); | |
exit(0); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 编译: | |
* gcc epoll_server.c -o epoll_server | |
* | |
* 运行: | |
* ./epoll_server | |
*/ | |
#include "stdio.h" | |
#include "stdlib.h" | |
#include "string.h" | |
#include "unistd.h" | |
#include "sys/types.h" | |
#include "sys/socket.h" | |
#include "sys/epoll.h" | |
#include "netinet/in.h" | |
#include "arpa/inet.h" | |
#include "fcntl.h" | |
#include "errno.h" | |
#define PORT 12345 // 要监听的端口 | |
#define BACKLOG 2 | |
#define MAXDATASIZE 1000 | |
#define OPEN_MAX 100 | |
int main(int argc, char *argv[]) | |
{ | |
struct epoll_event event; // 告诉内核要监听什么事件 | |
struct epoll_event wait_event; //内核监听完的结果 | |
//1.创建tcp监听套接字 | |
int sockfd = socket(AF_INET, SOCK_STREAM, 0); | |
//2.绑定sockfd | |
struct sockaddr_in my_addr; | |
bzero(&my_addr, sizeof(my_addr)); | |
my_addr.sin_family = AF_INET; | |
my_addr.sin_port = htons(PORT); | |
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr)); | |
//3.监听listen | |
listen(sockfd, 10); | |
//4.epoll相应参数准备 | |
int fd[OPEN_MAX]; | |
int i = 0, maxi = 0; | |
memset(fd,-1, sizeof(fd)); | |
fd[0] = sockfd; | |
int epfd = epoll_create(10); // 创建一个 epoll 的句柄,参数要大于 0, 没有太大意义 | |
if( -1 == epfd ){ | |
perror ("epoll_create"); | |
return -1; | |
} | |
event.data.fd = sockfd; //监听套接字 | |
event.events = EPOLLIN; // 表示对应的文件描述符可以读 | |
//5.事件注册函数,将监听套接字描述符 sockfd 加入监听事件 | |
int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event); | |
if(-1 == ret){ | |
perror("epoll_ctl"); | |
return -1; | |
} | |
struct epoll_event ev; | |
while(1) { | |
// 监视并等待多个文件(标准输入,udp套接字)描述符的属性变化(是否可读) | |
// 没有属性变化,这个函数会阻塞,直到有变化才往下执行,这里没有设置超时 | |
ret = epoll_wait(epfd, &wait_event, maxi+1, -1); | |
if(ret == -1) { | |
perror("epoll_wait"); | |
exit(-1); | |
} | |
//6.1监测sockfd(监听套接字)是否存在连接 | |
if(( sockfd == wait_event.data.fd ) | |
&& ( EPOLLIN == wait_event.events & EPOLLIN ) ) | |
{ | |
struct sockaddr_in cli_addr; | |
int clilen = sizeof(cli_addr); | |
//6.1.1 从tcp完成连接中提取客户端 | |
int connfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); | |
fcntl(connfd, F_SETFL, fcntl(connfd, F_GETFL) | O_NONBLOCK); | |
printf("Get an connect\n"); | |
//6.1.2 将提取到的connfd放入fd数组中,以便下面轮询客户端套接字 | |
for(i=1; i<OPEN_MAX; i++) | |
{ | |
if(fd[i] < 0) | |
{ | |
fd[i] = connfd; | |
event.data.fd = connfd; //监听套接字 | |
event.events = EPOLLIN; // 表示对应的文件描述符可以读 | |
//6.1.3.事件注册函数,将监听套接字描述符 connfd 加入监听事件 | |
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &event); | |
if(-1 == ret){ | |
perror("epoll_ctl"); | |
return -1; | |
} | |
break; | |
} | |
} | |
//6.1.4 maxi更新 | |
if(i > maxi) | |
maxi = i; | |
//6.1.5 如果没有就绪的描述符,就继续epoll监测,否则继续向下看 | |
if(--ret <= 0) | |
continue; | |
} | |
for(i=1; i<=maxi; i++) | |
{ | |
if(fd[i] < 0) | |
continue; | |
if(( fd[i] == wait_event.data.fd ) | |
&& ( EPOLLIN == wait_event.events & (EPOLLIN|EPOLLERR) )) | |
{ | |
int len = 0; | |
char buf[128] = ""; | |
//6.2.1接受客户端数据 | |
len = recv(fd[i], buf, sizeof(buf), 0); | |
if(len < 0) | |
{ | |
printf("Get Err %s\n", strerror(errno)); | |
if(errno == ECONNRESET) //tcp连接超时、RST | |
{ | |
printf("Connect close\n"); | |
close(fd[i]); | |
fd[i] = -1; | |
} | |
else | |
perror("read error:"); | |
} | |
else if(len == 0)//客户端关闭连接 | |
{ | |
printf("Errno: %s\n", strerror(errno)); | |
printf("Connect close\n"); | |
close(fd[i]); | |
fd[i] = -1; | |
} | |
else //正常接收到服务器的数据 | |
{ | |
printf("Get %s\n", buf); | |
} | |
//6.2.2所有的就绪描述符处理完了,就退出当前的for循环,继续poll监测 | |
ret--; | |
if(ret <= 0) | |
break; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 编译: | |
* gcc server.c -o server | |
* | |
* 运行: | |
* ./server | |
*/ | |
#include "stdio.h" | |
#include "stdlib.h" | |
#include "string.h" | |
#include "unistd.h" | |
#include "sys/types.h" | |
#include "sys/socket.h" | |
#include "netinet/in.h" | |
#include "arpa/inet.h" | |
#include "fcntl.h" | |
#include "errno.h" | |
#define PORT 12345 // 要监听的端口 | |
#define BACKLOG 2 | |
#define MAXDATASIZE 1000 | |
/** | |
* 每次收到请求就开一个线程 | |
*/ | |
void process_cli(int connectfd, struct sockaddr_in client); | |
int main(int argc, char const *argv[]) | |
{ | |
int listenfd, connectfd; /* socket descpiptors */ | |
pid_t pid; | |
struct sockaddr_in server; | |
struct sockaddr_in client; | |
int sin_size; | |
/* Create TCP socket */ | |
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { | |
perror("Creating socket failed"); | |
exit(1); | |
} | |
int opt = SO_REUSEADDR; | |
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); | |
bzero(&server, sizeof(server)); | |
server.sin_family = AF_INET; | |
server.sin_port = htons(PORT); | |
server.sin_addr.s_addr = htonl(INADDR_ANY); | |
if (bind(listenfd, (struct sockaddr*)&server, sizeof(struct sockaddr)) == -1) | |
{ | |
perror("Bind error\n"); | |
exit(1); | |
} | |
if (listen(listenfd, BACKLOG) == -1) | |
{ | |
perror("listen() error\n"); | |
exit(1); | |
} | |
sin_size = sizeof(struct sockaddr_in); | |
while(1) { | |
// 阻塞 | |
if ((connectfd = accept(listenfd, (struct sockaddr *)&client, &sin_size)) == -1) { | |
perror("accept error\n"); | |
} | |
if ((pid = fork()) > 0) { // pid > 0 说明为本线程 | |
close(connectfd); | |
continue; | |
} else if (pid == 0) { // 子线程, 处理收发 | |
close(listenfd); | |
process_cli(connectfd, client); | |
exit(0); | |
} else { | |
perror("fork error\n"); | |
exit(0); | |
} | |
} | |
close(listenfd); | |
return 0; | |
} | |
extern int errno; | |
void process_cli(int connectfd, struct sockaddr_in client) | |
{ | |
fcntl(connectfd, F_SETFL, fcntl(connectfd, F_GETFL) | O_NONBLOCK); | |
int num; | |
char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE]; | |
printf("You got a connection from %s .\n", inet_ntoa(client.sin_addr)); | |
char *s = "if it could be recvived"; | |
if (send(connectfd, s, strlen(s), 0) != strlen(s)) { | |
perror("Mismatch in number of sent bytes"); | |
exit(1); | |
} | |
num = recv(connectfd, cli_name, MAXDATASIZE, 0); | |
if (num == 0) { | |
close(connectfd); | |
printf("Client disconnected.\n"); | |
return; | |
} | |
cli_name[num - 1] = '\0'; | |
printf("Client's name is %s.\n", cli_name); | |
//while(send(connectfd, cli_name, strlen(cli_name), 0) == strlen(cli_name)) { | |
while(1){ | |
num = recv(connectfd, recvbuf, MAXDATASIZE, 0); | |
if(num <= 0) | |
printf("Err: %s\n", strerror(errno)); | |
else { | |
recvbuf[num] = '\0'; | |
printf("Received client(%s) message: %s\n", cli_name, recvbuf); | |
for (int i = 0; i < num - 1; ++i) { | |
sendbuf[i] = recvbuf[num - i - 2]; | |
} | |
} | |
sleep(2); // 暂停, 否则输出太多 | |
// 检测是否关闭 | |
int tester = recv(connectfd, recvbuf, MAXDATASIZE, MSG_PEEK | MSG_DONTWAIT); | |
printf("Tester: %d, ErrTester: %s\n", tester, strerror(errno)); | |
if (tester == 0) { | |
break; | |
} | |
sendbuf[num - 1] = '\0'; | |
send(connectfd, sendbuf, strlen(sendbuf), 0); | |
} | |
printf("Connect closed\n"); | |
close(connectfd); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment