Skip to content

Instantly share code, notes, and snippets.

@corvofeng
Created January 27, 2018 10:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save corvofeng/124b44334f831020ce1eade28cd7a650 to your computer and use it in GitHub Desktop.
Save corvofeng/124b44334f831020ce1eade28cd7a650 to your computer and use it in GitHub Desktop.
Client-Server
/**
* 编译:
* 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;
}
/**
* 编译:
* 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;
}
}
}
}
/**
* 编译:
* 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