Socket编程(C语言实现)—— Nginx支持Socket转发

 

搭建Nginx环境:
[root@localhost /]# cd /usr/local/src
[root@localhost src]# wget http://nginx.org/download/nginx-1.11.10.tar.gz


然后解压,解压完,根据文档提示需要使用这个参数--with-stream 来启用功能。


[root@localhost src]# ./configure  --prefix=/usr/local/nginx --with-stream 


然后,make,make install。

完成之后就是nginx配置配置文件啦,这个文档中有示例,可知与events模块平级,按照这做就好啦。


worker_processes  1;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
stream{
    upstream abc{
        server 172.18.8.196:11911;
    }
    server{
        listen 11911;
        proxy_pass abc;
    }
}


ok,保存退出,重启nginx使配置生效即可。到这里所有的操作就都完成啦,让我们拭目以待,看下结果吧。
socket的服务端与客户端可以通信

实现服务端可以向客户端发送信息,客户端接受到信息后,显示出来。用c#控制台程序实现。

服务端监听本机ip与端口,服务端代码如下:


class Program
    {
        static Socket sck = null;
        static void Main(string[] args)
        {             
            sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);    
            //监听本机ip        
            IPAddress ip = IPAddress.Parse("172.18.8.196");           
            IPEndPoint endPoint = new IPEndPoint(ip, int.Parse("11911"));            
            sck.Bind(endPoint);
            sck.Listen(10);
            Console.WriteLine("开启监听!");
            Thread thread = new Thread(JtSocket);
            thread.IsBackground = true;
            thread.Start();
            while (true)
            {              
                var msg = Console.ReadLine().Trim();
                if (msg != "")
                {
                    byte[] buffer = System.Text.Encoding.ASCII.GetBytes(msg); //将要发送的数据,生成字节数组。
                    accSck.Send(buffer);
                    Console.WriteLine("向客户端发送了:" + msg);
                }
            }
        }
        static Socket accSck = null;      
        static void JtSocket()
        {
            while (true)
            {               
                accSck = sck.Accept();               
                Console.WriteLine("链接成功!");
            }
        }
    }


客户端连接ip为nginx代理服务器ip,客户端如下:


 class Program
    {
        static Socket clientSocket = null;
        static Thread thread = null;
        static void Main(string[] args)
        {
            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //这里联通nginx代理服务器地址ip
            IPAddress ip = IPAddress.Parse("172.18.8.252");
            IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32("11911"));
            clientSocket.Connect(endpoint);
            thread = new Thread(ReceMsg);
            thread.IsBackground = true;
            thread.Start();
            Console.WriteLine("123");
            Console.ReadKey();
        }
        static void ReceMsg()
        {
            while (true)
            {
                byte[] buffer = new byte[1024 * 1024 * 2];
                clientSocket.Receive(buffer);
                string ReceiveMsg = System.Text.Encoding.UTF8.GetString(buffer).Substring(0,30);
                Console.WriteLine("接收到数据:" + ReceiveMsg);
            }
        }
    }

 

测试nginx转发socket结果

启动服务端--->显示:开启监听--->启动客户端----> 客户端显示:连接成功---->服务端输入:abc----->服务端:点击回车---->客户端显示:abc。如下

服务端:客户端:

至此所有的都已整个过程都已结束,功能实现。

工作中的遇到的问题:
server端:
 

/****************************************************************
简述:线程执行函数,创建socket并监听,对用户管理提供支持
参数:void *pvData
返回值:NULL
备注:无
*****************************************************************/
#define NGX_HTTP_MYACCESS_SOCK_PATH_STR "/usr/local/nginx/conf/waf/sock_un"
#define NGX_HTTP_MYACCESS_SOCK_QUEUESIZE 1024UL
#define NGX_HTTP_MYACCESS_EPOLL_LISTEN_NUM 10240UL
#define NGX_HTTP_MYACCESS_EPOLLEVENT_MAXNUM  1024UL
#define EPOLLIN 0x001
#define NGX_OK 0
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2
static void * _ngx_http_myaccess_thread_run(void *pvData)
{
    int i = 0;
    int iTmpFd   = 0;
    int iRetNum  = 0;
    int iSockFd  = 0;
    int iEpollFd = 0;
    mode_t mod = {0};
    socklen_t iAddrLen = 0;
    struct sockaddr_un stAddr = {0};
    struct epoll_event stListen_Event = {0};
    struct epoll_event astEpollEvent[NGX_HTTP_MYACCESS_EPOLLEVENT_MAXNUM] = {{0}};

    /* 删除原来的socket文件 */
    remove(NGX_HTTP_MYACCESS_SOCK_PATH_STR);

    /* 设置umask,使创建的sock文件的权限为0777 */
    mod = umask(0);

    /* 创建socket */
    iSockFd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(0 > iSockFd)
    {
        return NULL;
    }

    /* 绑定 */
    stAddr.sun_family = AF_UNIX;
    ngx_memcpy(stAddr.sun_path, NGX_HTTP_MYACCESS_SOCK_PATH_STR, sizeof(stAddr.sun_path));
    if(0 > bind(iSockFd, (void *)&stAddr, sizeof(stAddr)))
    {
        close(iSockFd);
        return NULL;
    }

    /* 恢复原有的umask umask:设置限制新文件权限*/
    umask(mod);

    /* 监听 */
    if(0 >listen(iSockFd, NGX_HTTP_MYACCESS_SOCK_QUEUESIZE))
    {
        close(iSockFd);
        return NULL;
    }

    /* 创建EPOLL监听 */
    iEpollFd = epoll_create(NGX_HTTP_MYACCESS_EPOLL_LISTEN_NUM);
    if(0 > iEpollFd)
    {
        close(iSockFd);
        return NULL;
    }

    /* 将socket加入epoll监听列表 */
    stListen_Event.data.fd = iSockFd;
    stListen_Event.events  = EPOLLIN;
    if(0 > epoll_ctl(iEpollFd, EPOLL_CTL_ADD, iSockFd, &stListen_Event))
    {
        close(iSockFd);
        close(iEpollFd);
        return NULL;
    }

    while(1)
    {
        iRetNum = epoll_wait(iEpollFd, astEpollEvent, NGX_HTTP_MYACCESS_EPOLLEVENT_MAXNUM, -1);
        for(i = 0; i < iRetNum; i++)
        {
            if(iSockFd == astEpollEvent[i].data.fd)
            {
                /* 接受新的连接 */
                iAddrLen = sizeof(stAddr);
                iTmpFd = accept(iSockFd, (void *)&stAddr, &iAddrLen);

                /* 将新的连接加入到epoll的监听列表中 */
                stListen_Event.data.fd = iTmpFd;
                stListen_Event.events  = EPOLLIN;
                if(0 > epoll_ctl(iEpollFd, EPOLL_CTL_ADD, iTmpFd, &stListen_Event))
                {
                    close(iTmpFd);
                    continue;
                }
            }
            else if(EPOLLIN == astEpollEvent[i].events)
            {
                /* 处理用户输入,若返回失败,清除监听关闭链接 */
                if(NGX_OK != _ngx_http_myaccess_EpollIn(astEpollEvent[i].data.fd, g_pstOnLineHashTb))
                {
                    epoll_ctl(iEpollFd, EPOLL_CTL_DEL, astEpollEvent[i].data.fd, &astEpollEvent[i]);
                    close(astEpollEvent[i].data.fd);
                }
            }
            else
            {
                epoll_ctl(iEpollFd, EPOLL_CTL_DEL, astEpollEvent[i].data.fd, &astEpollEvent[i]);
                close(astEpollEvent[i].data.fd);
            }
        }
    }

    close(iSockFd);
    return NULL;
}

client端:

#include "userSock.h"

int user_socket_action(int argc , char **argv, char *pcName)
{
		int sockfd;
		int tempfd;
		struct sockaddr_un s_addr_un;
		char data_send[BUFFER_LENGTH] = {0};
		char data_recv[BUFFER_LENGTH] = {0};

		sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
		if(sockfd == -1)
		{
				fprintf(stderr,"socket error!\n");
				exit(1);
		}

		s_addr_un.sun_family = AF_UNIX;
		memcpy(s_addr_un.sun_path, "/usr/local/nginx/conf/waf/sock_un", strlen("/usr/local/nginx/conf/waf/sock_un"));

		tempfd = connect(sockfd, (struct sockaddr *)&s_addr_un,sizeof(s_addr_un));
		//tempfd = connect(sockfd, "/usr/local/nginx/conf/waf/sock_un",0);
		if(tempfd == -1)
		{
				fprintf(stderr,"Connect error!\n");
				close(sockfd);
				exit(1);
		}


		tempfd = write(sockfd,pcName,BUFFER_LENGTH);
		if(tempfd == -1)
		{
				fprintf(stderr,"Write error!\n");
				close(sockfd);
				exit(1);
		}
		
		tempfd = read(sockfd,data_recv,BUFFER_LENGTH);
		assert(tempfd != -1);
		printf("%s\n",data_recv);
		memset(data_send,0,BUFFER_LENGTH);
		memset(data_recv,0,BUFFER_LENGTH);

		close(sockfd);
		return 0;
}

(*****还未经测试*****  随后再更新)

参考链接:https://m.linuxidc.com/Linux/2017-03/141318.htm&http:/m.linuxidc.com/Linux/2017-03/141318.htm

你可能感兴趣的:(C,语言,协议)