您的位置:首页 > 运维架构 > Linux

SOCKS5实现(二)

2018-03-03 17:29 916 查看
上一篇文章介绍了一些基本概念,以及简单的用现有的软件搭建透明代理。这篇文章简单说下在linux下用C++进行socket编程的过程。

参考:

C++ Socket : http://lengly.top/archives/155

C++ epoll : https://gist.github.com/dtoma/417ce9c8f827c9945a9192900aff805b

第一步是makefile的编写了,可以参考我的文章:makefile的使用

第二步是理解socket编程的一些公共函数、API,建立连接有几个过程:

服务器:

create: socket(AF_INET,SOCK_STREAM,0)

调整SOCK_STREAM这个位置的参数就可以建立TCP、UDP、RAW socket

setOptions : int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov, unsigned int ol);

允许复用地址:SO_REUSEADDR

bind : int bind(int sockfd, const struct sockaddr * my_addr, socklen_t addrlen);

将一个本地地址与一个套接口绑定,如果client端不需要指定自己的地址和端口则无需进行这个设置

listen

connect: int connect (int sockfd,struct sockaddr * serv_addr, int addrlen);

accept

recv

send

close

客户端:

creat

connect

send

recv

close

这里贴一下代码~

Makefile

all : main.o server.o test.o client.o
g++ -o server main.o server.o
g++ -o test test.o client.o

main.o : main.cc server.h
g++ -c main.cc

server.o : server.cc server.h
g++ -c server.cc

test.o : test.cc client.h
g++ -c test.cc

client.o: client.cc client.h
g++ -c client.cc

clean:
rm -f *.o *.so server test


//
//  server.cc
//
//  Created by Yeshen on 1/03/2018.
//  Copyright © 2018 yeshen.org. All rights reserved.
//

#include "server.h"

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <netdb.h>

#define SERVER_PORT 2018
#define MAX_CONNECTION 10
#define MAX_DATA_SIZE 1000
#define MAX_EVENT 32

using namespace std;

Server::Server(){
this->port = 2018;
this->running = false;
};

Server::Server(int port){
this->port = port;
this->running = false;
};

void Server::start(){
cout << "start" << endl;

//create and bind
int sock_fd,client_fd;
int sin_size;
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;

if((sock_fd = socket(AF_INET,SOCK_STREAM,0))==-1){
perror("fail to create socket");
exit(1);
}
long flag = 1;
setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag));
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(SERVER_PORT);
local_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(local_addr.sin_zero),8);

if(bind(sock_fd,(struct sockaddr *)&local_addr,sizeof(struct sockaddr)) == -1){
perror("fail to bind socket");
exit(1);
}

int sock_flags = fcntl(sock_fd,F_GETFL,0);
sock_flags |= O_NONBLOCK;
if(fcntl(sock_fd, F_SETFL, sock_flags) == -1){
perror("fail to set nonblock");
exit(1);
}

//listen
if(listen(sock_fd,MAX_CONNECTION) == -1){
perror("fail to listen");
exit(1);
}

int epoll_fd;
if((epoll_fd = epoll_create1(0))==-1){
perror("fail to create epoll");
exit(1);
}

struct epoll_event event,events[MAX_EVENT];
event.data.fd = sock_fd;
event.events = EPOLLIN | EPOLLET;
if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,sock_fd,&event) == -1){
perror("fail to create epoll ctl");
exit(1);
}

while(true){
int n = epoll_wait(epoll_fd,events,MAX_EVENT,-1);
for(int i =0;i<n; ++i){
if(events[i].events & EPOLLERR ||
events[i].events & EPOLLHUP ||
!(events[i].events & EPOLLIN) ){
perror("error in epoll event");
close(events[i].data.fd);
}else if(sock_fd == events[i].data.fd){
while(true){
struct sockaddr in_addr;
socklen_t in_len = sizeof(in_addr);
int in_fd;
if((in_fd = accept(sock_fd,&in_addr,&in_len)) == -1){
if(errno == EAGAIN || errno == EWOULDBLOCK){
continue;
}else{
perror("accept failed");
continue;
}
}
std::string hbuf(NI_MAXHOST,'\0');
std::string sbuf(NI_MAXSERV,'\0');
if(getnameinfo(&in_addr,in_len,
const_cast<char*>(hbuf.data()),hbuf.size(),
const_cast<char*>(sbuf.data()),sbuf.size(),
NI_NUMERICHOST | NI_NUMERICSERV) == 0 ){

std::cout << "Accepted:" << in_fd << "(host=" << hbuf << ", port=" << sbuf << ")" << endl;
}

int in_flags = fcntl(in_fd,F_GETFL,0);
in_flags |= O_NONBLOCK;
if(fcntl(in_fd, F_SETFL, in_flags) == -1){
std::cout << "nonblocking" << "(host=" << hbuf << endl;
continue;
}

event.data.fd = in_fd;
event.events = EPOLLIN | EPOLLET;
if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,in_fd,&event) ==-1){
printf("fail to add epoll\n");
continue;
}
if(send(in_fd,"Hello, you are connected!\n",26,0) == -1){
printf("fail to send\n");
continue;
}
break;
}
}else{
int fd = events[i].data.fd;
while(true){
char buf[512];
int count = read(fd,buf,512);
if(count == -1){
if(errno == EAGAIN){
continue;
}
}else if(count ==0){
printf("close %d\n",fd);
close(fd);
continue;
}else{
std::cout <<"says:" <<  buf << endl;
}
break;
}
}
}
}
close(sock_fd);
}

void Server::stop(){
cout << "stop" << endl;
}


//
//  client.cc
//
//  Created by Yeshen on 1/03/2018.
//  Copyright © 2018 yeshen.org. All rights reserved.
//

#include <iostream>
#include <string>
#include "client.h"

#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MAX_DATA_SIZE 1000

using namespace std;

Client::Client(){
this->ip = "127.0.0.1";
this->port = 2018;
};

Client::Client(const char * ip, int port){
this->ip = ip;
this->port = port;
};

void Client::run(){
cout << "run" << this->ip << this->port << endl ;
int sock_fd = -1;
char buf[MAX_DATA_SIZE];
int recvbytes,sendbytes,len;

in_addr_t server_ip = inet_addr(this->ip);
in_port_t server_port = atoi("2018");//TODO
in_addr_t my_ip = inet_addr(this->ip);
in_port_t my_port = atoi("2028");

if((sock_fd = socket(AF_INET,SOCK_STREAM,0)) == -1){
perror("fail to creat socket");
exit(1);
}

long flag = 1;
setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag));

struct sockaddr_in my_addr;
my_addr.sin_addr.s_addr = my_ip;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(my_port);

if(bind(sock_fd,(sockaddr*)&my_addr,sizeof(sockaddr)) == -1){
perror("fail to bind socket");
exit(1);
}

struct sockaddr_in server_addr;
server_addr.sin_addr.s_addr = server_ip;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
printf("try to connect %s:%u\n",
inet_ntoa(server_addr.sin_addr),
ntohs(server_addr.sin_port));

if(connect(sock_fd,
(struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1){
perror("fail to connect");
exit(1);
}

if(send(sock_fd,"here\n",4,0) == -1){
perror("fail to send");
}

if((recvbytes=recv(sock_fd,buf,MAX_DATA_SIZE,0)) == -1){
perror("fail to recv");
exit(1);
}
buf[recvbytes] = '\0';
printf("Received: %s",buf);

close(sock_fd);
exit(0);
}


项目开源在 github -> wuyisheng/socks

当前代码:commit 0331d8d0817ae3ba7ef663756bfbcc7435d31c78

扫码关注,实时互动

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C/C++ socket linux epoll