Linux下Socket数据转发技巧 (linux socket转发)

Socket是网络通信的重要组成部分,许多网络应用程序都采用Socket进行数据通信。Linux作为一个开源操作系统,其内核源代码提供了丰富的网络编程接口和工具函数,使得开发者能够快速高效地开发网络应用程序。本文将探讨一种常见的网络编程应用——Socket数据转发技巧。

一、Socket数据转发的基本原理

Socket数据转发就是将网络数据包从一个Socket接口转发到另一个Socket接口。这个过程中,需要涉及到底层的套接字编程、数据包格式解析、IPv4/IPv6协议栈处理等内容。其中最基本的操作就是通过Socket接口收发数据。

在Linux下,Socket是通过文件描述符来进行管理的。当一个客户端连接到服务器时,会产生一个新的Socket,服务器会利用该Socket来和客户端进行通信。针对Socket数据转发,可以使用系统调用函数`accept()`和`connect()`来建立Socket连接,使用`recv()`和`send()`函数来接收和发送数据。

二、Socket数据转发的应用场景

Socket数据转发作为一种网络编程技巧,主要用于如下几个场景:

1. 网络代理:通过Socket数据转发,可以实现各种形式的网络代理。例如,HTTP代理、FTP代理、SOCKS代理等。当客户端发起请求时,代理服务器会将请求转发到目标服务器,然后接收响应并返回给客户端。

2. 负载均衡:当一台服务器不能满足全部请求时,可以利用Socket数据转发来分发请求到多台服务器上,以达到负载均衡的目的。负载均衡算法可以是轮询、加权轮询、随机、最小连接数等。

3. 防火墙透明代理:防火墙在网络安全中起着重要的作用。有时候需要修改IP数据包的源地址和目的地址,以实现透明代理的目的。使用Socket数据转发技巧,可以轻松地实现IP数据包的转发和修改。

三、 Socket数据转发的实现步骤

本部分将介绍在Linux环境下,如何使用Socket数据转发技巧来实现网络代理。具体实现步骤如下:

1. 建立监听Socket。

“`c

int socket_fd = socket(AF_INET, SOCK_STREAM, 0);

if(socket_fd == -1){

perror(“socket”);

exit(EXIT_FLURE);

}

struct sockaddr_in server_addr;

bzero(&server_addr, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(8080);

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

if(bind(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){

perror(“bind”);

exit(EXIT_FLURE);

}

if(listen(socket_fd, 5) == -1){

perror(“listen”);

exit(EXIT_FLURE);

}

“`

使用`socket()`函数创建一个TCP套接字,并绑定到本地服务器地址。然后使用`listen()`函数监听端口8080。

2. 接受客户端连接。

“`c

int client_fd = accept(socket_fd, (struct sockaddr*)&client_addr, &addrlen);

if(client_fd == -1){

perror(“accept”);

exit(EXIT_FLURE);

}

“`

使用`accept()`函数接收客户端连接,并获取客户端的IP地址和端口号。

3. 连接远程服务器。

“`c

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

if(server_fd == -1){

perror(“socket”);

exit(EXIT_FLURE);

}

struct sockaddr_in server_addr;

bzero(&server_addr, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(80);

inet_pton(AF_INET, “10.0.0.1”, &server_addr.sin_addr);

if(connect(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){

perror(“connect”);

exit(EXIT_FLURE);

}

“`

使用`socket()`函数创建一个TCP套接字,并连接到远程服务器,在本例中远程服务器地址为10.0.0.1,端口号为80。

4. 接收来自客户端的数据,并将其发送到远程服务器。

“`c

char buffer[MAX_BUF_SIZE];

int n = recv(client_fd, buffer, MAX_BUF_SIZE, 0);

if(n == -1){

perror(“recv”);

exit(EXIT_FLURE);

}

if(send(server_fd, buffer, n, 0) == -1){

perror(“send”);

exit(EXIT_FLURE);

}

“`

使用`recv()`函数从客户端接收数据,然后使用`send()`函数将数据发送到远程服务器。

5. 接收来自远程服务器的数据,并将其发送到客户端。

“`c

n = recv(server_fd, buffer, MAX_BUF_SIZE, 0);

if(n == -1){

perror(“recv”);

exit(EXIT_FLURE);

}

if(send(client_fd, buffer, n, 0) == -1){

perror(“send”);

exit(EXIT_FLURE);

}

“`

使用`recv()`函数从远程服务器接收数据,然后使用`send()`函数将数据发送到客户端。

6. 关闭套接字。

“`c

close(client_fd);

close(server_fd);

“`

使用`close()`函数关闭套接字,释放资源。

实现以上步骤后,通过向监听的socket发送数据,应该能够通过本机作为转发者将数据转发到远程服务器上了。

四、 Socket数据转发的应用实例

以下是一个简单的网页代理程序,它监听本地8080端口,将客户端发来的HTTP请求转发到远程web服务器上,并将响应返回给客户端。

“`c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define MAX_BUF_SIZE 1024

int mn(int argc, char *argv[])

{

if(argc != 2){

printf(“Usage: %s \n”, argv[0]);

return 1;

}

int socket_fd = socket(AF_INET, SOCK_STREAM, 0);

if(socket_fd == -1){

perror(“socket”);

return EXIT_FLURE;

}

struct sockaddr_in server_addr;

bzero(&server_addr, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(8080);

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

if(bind(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){

perror(“bind”);

return EXIT_FLURE;

}

if(listen(socket_fd, 5) == -1){

perror(“listen”);

return EXIT_FLURE;

}

printf(“Web proxy listening on port 8080…\n”);

while(1){

socklen_t addrlen = sizeof(struct sockaddr_in);

struct sockaddr_in client_addr;

int client_fd = accept(socket_fd, (struct sockaddr*)&client_addr, &addrlen);

if(client_fd == -1){

perror(“accept”);

return EXIT_FLURE;

}

char buffer[MAX_BUF_SIZE];

int n = recv(client_fd, buffer, MAX_BUF_SIZE, 0);

if(n == -1){

perror(“recv”);

return EXIT_FLURE;

}

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

if(server_fd == -1){

perror(“socket”);

return EXIT_FLURE;

}

struct sockaddr_in remote_addr;

bzero(&remote_addr, sizeof(remote_addr));

remote_addr.sin_family = AF_INET;

remote_addr.sin_port = htons(80);

inet_pton(AF_INET, argv[1], &remote_addr.sin_addr);

if(connect(server_fd, (struct sockaddr*)&remote_addr, sizeof(remote_addr)) == -1){

perror(“connect”);

return EXIT_FLURE;

}

if(send(server_fd, buffer, n, 0) == -1){

perror(“send”);

return EXIT_FLURE;

}

while(1){

n = recv(server_fd, buffer, MAX_BUF_SIZE, 0);

if(n == -1){

perror(“recv”);

break;

}

if(n == 0){ // 服务器关闭连接

close(server_fd);

break;

}

if(send(client_fd, buffer, n, 0) == -1){ //将响应发送到客户端

perror(“send”);

return EXIT_FLURE;

}

}

close(client_fd);

}

return 0;

}

“`

运行该程序后,可以在浏览器中设置代理服务器地址为本机IP地址和8080端口,就可以通过该网页代理程序进行数据转发了。

五、

相关问题拓展阅读:

Linux中 socket聊天室,给客户端发消息

这题目液搜是Linux Socket 很普遍的练习

你没贴代码,不知道问题在哪?

请试试下腊简面 Server.c and Client.c

服务器:server.c

#include

#include// 包含套接字函数库

#include

#include// 包含AF_INET相关结构

#include// 包含AF_INET相关操作的函数

#include

#include

#include

#include

#include

#define PORT;

#define MYKEY

#define SIZE

int main()

{

int shmid;

char *shmaddr;//定义子进程共用的共享内存

shmid = shmget(MYKEY, SIZE, IPC_CREAT | 0600);

shmaddr= (char *) shmat(shmid, 0, 0);

if(shmid==-1)

{

printf(“shmid error\n”);

}

memset(shmaddr,0,SIZE);

int i=0;

char buf;

memset(buf,0,100);

int server_sockfd,client_sockfd;

int server_len,client_len;

struct sockaddr_in server_sockaddr,client_sockaddr;

server_sockfd = socket(AF_INET,SOCK_STREAM, 0); // 定义套接字类型

server_sockaddr.sin_family=AF_INET;

server_sockaddr.sin_port=PORT;

server_sockaddr.sin_addr.s_addr=INADDR_ANY;

server_len=sizeof(server_sockaddr);

//允许重复使用本地地址和套接字绑定

int j=1;

setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&j,sizeof(j));

//绑定端口

if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,server_len)==-1)

{

perror(“bind:”);

exit(1);

}

if(listen(server_sockfd,5)==-1)

{

perror(“listen:”);

exit(1);

}

printf(“Listening…\n”);

client_len=sizeof(client_sockaddr);

pid_t ppid,pid;

while(1)

{

if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&client_sockaddr,&client_len))==-1)

{

perror(“accept error:”);

exit(1);

}

printf(“%s登录服务器\n”,inet_ntoa(client_sockaddr.sin_addr));

ppid=fork();

if(ppid==-1)

{

printf(“fork 1 failed:”);

}

if(ppid==0) //子进程用于接收客户端信息并发送

{

pid=fork();

if(pid==-1)

{

printf(“fork 2 failed:”);

exit(1);

}

int recvbytes;

if(pid==0)//子子进程用于接收消息

{

while(1)

{

if((recvbytes=recv(client_sockfd,buf,100,0))==-1)

{

perror(“read client_sockfd failed:”);

}

// printf(“recvbytes=%d\n”,recvbytes);

usleep(10000);

printf(“client send buf=%s\n”,buf);

for(i=0;i0) //子进程用于发送消息

{

while(1)

{

if(*(shmaddr+i*100)!=0)

{

// strcpy(&buf,shmaddr+100*i);

// buf++;

write(client_sockfd,shmaddr,SIZE);

// send(client_sockfd,buf,strlen(buf),0);

// printf(“the server is send buf=%c”,buf);

// printf(“send client :%s\n”,(shmaddr+i*100)) ;

i++;

}

}

}

}

if(ppid>0)//总父进程返回等待接收消息

{

close(client_sockfd);

}

}

}

客户端:client.c

#include

#include// 包含套接字函数库

#include

#include// 包含AF_INET相关结构

#include// 包含AF_INET相关操作的函数

#include

#include

#include

#define PORT 8888

#define IP_ADDR “192.168.110.185”

#define SIZE 10240

int main()

{

struct tm *timeptr;

time_t timeval;

char tm;

//(void)time(&timeval);

//printf(“the date is %s\n”,ctime(&timeval));

// printf(“The time is %s\n”,tm);

int sockfd; // 用于保存客户套接字标识符

int len;// 用于客户消息长度

struct sockaddr_in address; // 定义客户套接字地址

int result;

sockfd = socket(AF_INET,SOCK_STREAM, 0); // 定义套接字类型

address.sin_family = AF_INET; // 定义套接字地址中的域

address.sin_addr.s_addr = inet_addr(IP_ADDR);// 定义套接字地址

address.sin_port = htons(PORT); // 定义套接字端口

char buf; // 定义要传送的消息

memset(buf,0,100);

char str;//存贮输入的语句

char shmaddr; //接受服务器发送的全部聊天数据

int i=0;

char myname;

char say={“说:”};

printf(“欢迎来到聊天室,请输入你的姓名:\n”);

scanf(“%s”,myname);

len = sizeof(address);

result = connect(sockfd, (struct sockaddr *) &address, len); // 请求连接

if (result == -1)

{

perror(“Connect failed”);

return 1;

}

printf(“%s成功登录服务器:\n”,myname);

pid_t pid;

pid=fork();

if(pid==-1)

{

printf(“fork failed”);

}

int sendbytes=0;

if(pid==0)//子进程用于发送数据

{

while(1)

{

printf(“请输入语句:\n”);

scanf(“%s”,str);

(void)time(&timeval);

strcpy(tm,ctime(&timeval));

strcpy(buf,myname);//姓名传入buf中

strcat(buf,tm); //时间传入buf中

strcat(buf,say);

strcat(buf,str); //语句传入bufz中

//read(0,buf,strlen(buf));

// send(sockfd,buf,strlen(buf),0);

// getchar();

if((sendbytes=write(sockfd, buf, 100))==-1)

{

perror(“send to server failed:”);

} // 向服务器传送消息

// printf(“sendbytes=%d\n”,sendbytes);

// printf(“buf=%s\n”,buf);

// printf(“input buf=%s\n”,buf);

usleep(1000);

memset(buf,0,100);

memset(tm,0,50);

}

}

if(pid>0) //父进程用于接受消息并读取

{

while(1)

{

read(sockfd,shmaddr,SIZE);

// printf(“server send shmaddr=%s\n”,shmaddr);

if(*(shmaddr+i*100)!=0)

{

printf(“%s\n”,(shmaddr+i*100)) ;

i++;

}

usleep(1000);

}

}

close(sockfd);

return 0;

}

//下面是一个实例

/**    

* socket.io chat    

*    

*/    

     

var web = require(‘QuickWeb’);    

     

// undefined    

var _ = undefined;     

     

/**    

 * 创建一个房间    

 *    

 * @param {string} room 房间名称    

 * @param {socket.io} io socket.io实例    

 */    

var Room = module.exports = function (room, io) {    

// 初始化socket.io实例,仅在之一次创建房间时需要设置io参数    

if (typeof io != ‘undefined’)    

Room.prototype.io = io;    

var io = this.io;    

   

// 房间成员列表    

var nicknames = this.nicknames = {};    

var onlinesum = this.onlinesum = 0;    

   

// 握手验证,如果是登录用户,则自动获取其昵称    

io.set(‘authorization’, function (handshakeData, callback) {    

// 通过客户端的cookie字符串来获取其session数据    

var sessionObject = handshakeData.sessionObject = web.session.getByCookie(handshakeData.headers.cookie);    

   

// 如果不是登录用户,则自动为其设置一个昵称    

var nickname = sessionObject.data.nickname;    

if (typeof nickname != ‘string’ || nickname == ”)    

nickname = ‘#’ + Math.floor(Math.random() * 1000) + ” + (new Date().getTime() %);    

sessionObject.data.nickname = 配带nickname;    

   

callback(null, true);    

});    

   

/** 连接处理 */    

var connectionHandle = function (socket) {    

onlinesum++;    

// 获取session    

var session = socket.handshake.sessionObject.data;    

var nickname = session.nickname;    

   

// 保持session,以免session过期    

var hold_session = socket.handshake.sessionObject.hold;    

   

/** 刷新在线列表 */    

refresh_online = function () {    

var n = 辩卖凳;    

for (var i in nicknames)    

n.push(i);    

socket.broadcast.emit(‘online list’, n);    

socket.emit(‘online list’, n);    

}    

   

// 新成员加入时,通知其他成员    

nicknames = socket;    

refresh_online();    

socket.broadcast.emit(‘system message’, nickname + ‘回来了,大家赶紧去喷他~~’);    

   

/** 公共消息 */    

socket.on(‘public message’, function (msg, cb) {    

hold_session();    

var timestamp = new Date().getTime();    

socket.broadcast.emit(‘public message’, nickname, msg, timestamp);    

cb();    

});    

   

/** 私人消息 */    

socket.on(‘private message’, function (to, msg, cb) {    

hold_session();    

var timestamp = new Date().getTime();    

var err = ”;    

for (var i in to) {    

var target = nicknames>;    

if (target) {    

cb();    

target.emit(‘private message’, nickname, msg, timestamp);   携旅 

}    

else {    

err += ‘“’ + to + ‘”不在线\n’;    

}    

}    

if (err != ”)    

cb(err);    

});    

   

/** 断开来连接 */    

socket.on(‘disconnect’, function () {    

delete nicknames;    

onlinesum–;    

socket.broadcast.emit(‘system message’, nickname + ‘悄悄地离开了。。。’);    

refresh_online();    

});    

   

/** 命令 */    

socket.on(‘command’, function (args, cb) {    

if (args.length 

#include// 包含套接字函数库

#include

#include// 包含AF_INET相关结构

#include// 包含AF_INET相关操作的函数

#include

#include

#include

#include

#include

#define PORT;

#define MYKEY

#define SIZE

int main()

{

int shmid;

char *shmaddr;//定义子进程共用的共享内存

shmid = shmget(MYKEY, SIZE, IPC_CREAT | 0600);

shmaddr= (char *) shmat(shmid, 0, 0);

if(shmid==-1)

{

printf(“shmid error\n”);

}

memset(shmaddr,0,SIZE);

int i=0;

char buf;

memset(buf,0,100);

int server_sockfd,client_sockfd;

int server_len,client_len;

struct sockaddr_in server_sockaddr,client_sockaddr;

server_sockfd = socket(AF_INET,SOCK_STREAM, 0); // 定义套接字类型

server_sockaddr.sin_family=AF_INET;

server_sockaddr.sin_port=PORT;

server_sockaddr.sin_addr.s_addr=INADDR_ANY;

server_len=sizeof(server_sockaddr);

//允许重复使用本地地址和套接字绑定

int j=1;

setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&j,sizeof(j));

//绑定端口

if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,server_len)==-1)

{

perror(“bind:”);

exit(1);

}

if(listen(server_sockfd,5)==-1)

{

perror(“listen:”);

exit(1);

}

printf(“Listening…\n”);

client_len=sizeof(client_sockaddr);

pid_t ppid,pid;

while(1)

{

if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&client_sockaddr,&client_len))==-1)

{

perror(“accept error:”);

exit(1);

}

printf(“%s登录服务器\n”,inet_ntoa(client_sockaddr.sin_addr));

ppid=fork();

if(ppid==-1)

{

printf(“fork 1 failed:”);

}

if(ppid==0) //子进程用于接收客户端信息并发送

{

pid=fork();

if(pid==-1)

{

printf(“fork 2 failed:”);

exit(1);

}

int recvbytes;

if(pid==0)//子子进程用于接收消息

{

while(1)

{

if((recvbytes=recv(client_sockfd,buf,100,0))==-1)

{

perror(“read client_sockfd failed:”);

}

// printf(“recvbytes=%d\n”,recvbytes);

usleep(10000);

printf(“client send buf=%s\n”,buf);

for(i=0;i0) //子进程用于发送消息

{

while(1)

{

if(*(shmaddr+i*100)!=0)

{

// strcpy(&buf,shmaddr+100*i);

// buf++;

write(client_sockfd,shmaddr,SIZE);

// send(client_sockfd,buf,strlen(buf),0);

// printf(“the server is send buf=%c”,buf);

// printf(“send client :%s\n”,(shmaddr+i*100)) ;

i++;

}

}

}

}

if(ppid>0)//总父进程返回等待接收消息

{

close(client_sockfd);

}

}

}

客户端:client.c

#include

#include// 包含套接字函数库

#include

#include// 包含AF_INET相关结构

#include// 包含AF_INET相关操作的函数

#include

#include

#include

#define PORT 8888

#define IP_ADDR “192.168.110.185”

#define SIZE 10240

int main()

{

struct tm *timeptr;

time_t timeval;

char tm;

//(void)time(&timeval);

//printf(“the date is %s\n”,ctime(&timeval));

// printf(“The time is %s\n”,tm);

int sockfd; // 用于保存客户套接字标识符

int len;// 用于客户消息长度

struct sockaddr_in address; // 定义客户套接字地址

int result;

sockfd = socket(AF_INET,SOCK_STREAM, 0); // 定义套接字类型

address.sin_family = AF_INET; // 定义套接字地址中的域

address.sin_addr.s_addr = inet_addr(IP_ADDR);// 定义套接字地址

address.sin_port = htons(PORT); // 定义套接字端口

char buf; // 定义要传送的消息

memset(buf,0,100);

char str;//存贮输入的语句

char shmaddr; //接受服务器发送的全部聊天数据

int i=0;

char myname;

char say={“说:”};

printf(“欢迎来到聊天室,请输入你的姓名:\n”);

scanf(“%s”,myname);

len = sizeof(address);

result = connect(sockfd, (struct sockaddr *) &address, len); // 请求连接

if (result == -1)

{

perror(“Connect failed”);

return 1;

}

printf(“%s成功登录服务器:\n”,myname);

pid_t pid;

pid=fork();

if(pid==-1)

{

printf(“fork failed”);

}

int sendbytes=0;

if(pid==0)//子进程用于发送数据

{

while(1)

{

printf(“请输入语句:\n”);

scanf(“%s”,str);

(void)time(&timeval);

strcpy(tm,ctime(&timeval));

strcpy(buf,myname);//姓名传入buf中

strcat(buf,tm); //时间传入buf中

strcat(buf,say);

strcat(buf,str); //语句传入bufz中

//read(0,buf,strlen(buf));

// send(sockfd,buf,strlen(buf),0);

// getchar();

if((sendbytes=write(sockfd, buf, 100))==-1)

{

perror(“send to server failed:”);

} // 向服务器传送消息

// printf(“sendbytes=%d\n”,sendbytes);

// printf(“buf=%s\n”,buf);

// printf(“input buf=%s\n”,buf);

usleep(1000);

memset(buf,0,100);

memset(tm,0,50);

}

}

if(pid>0) //父进程用于接受消息并读取

{

while(1)

{

read(sockfd,shmaddr,SIZE);

// printf(“server send shmaddr=%s\n”,shmaddr);

if(*(shmaddr+i*100)!=0)

{

printf(“%s\n”,(shmaddr+i*100)) ;

i++;

}

usleep(1000);

}

}

close(sockfd);

return 0;

关于linux socket转发的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » Linux下Socket数据转发技巧 (linux socket转发)