Linux 网络编程 tcp server 笔记

一、TCP 服务器的创建

在 Linux 上创建一个简单的 tcp 服务器步骤如下:

①创建套接字

②将套接字绑定到 IP 地址和端口号

③监听来自客户端的连接

④接受连接并创建新的套接字用于与客户端通信

⑤通过新建的套接字发送和接收数据

⑥关闭套接字

流程框图如下:

Linux 网络编程 tcp server 笔记_第1张图片

根据以上介绍可以创建tcp server的示例,分为服务器-单客户端和服务器-多客户端。

二、服务器-单客户端示例

tcp server示例代码如下:

#include 
#include 
#include 
#include 
#include  //struct sockaddr_in
#include  //inet_addr()
#include //close()




#define MY_PRINTF(argv)   do{\
                                printf("file:%s --- function:%s --- line:%d\r\n",__FILE__,__FUNCTION__,__LINE__);\
                                printf("%s\r\n",argv);\
                            }while(0);
#define MYPORT 5000
//tcp server demo
 int main(int argc,char *argv[])
{
     int sockefd;
     int sockenewfd;
     int ret;
     int enable=1;


     struct sockaddr_in my_addr;//本地地址-服务器


     struct sockaddr_in remote_addr;//远端地址-客户端
     int remote_addr_len;


     char buf[1024];


     sockefd=socket(AF_INET,SOCK_STREAM,0);// 套接字
     if(sockefd<0)
     {
         MY_PRINTF("socket err !! ");
         return -1;
     }
    if (setsockopt(sockefd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(enable)) == -1) 
     {
        close(sockefd);
        MY_PRINTF(" setsockopt  err !! ");
        return -1;
    }
     MY_PRINTF("socket ok !! ");


     //本地地址
     my_addr.sin_family=AF_INET;    
     my_addr.sin_port=htons(MYPORT);//0:随机端口
     my_addr.sin_addr.s_addr=INADDR_ANY;//inet_addr("192.168.164.157");//INADDR_ANY:本机 ip  // inet_addr():IP 地址的字符串转换成一个无符号长整型
     bzero(my_addr.sin_zero,sizeof(my_addr.sin_zero));




     ret=bind(sockefd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));//绑定   //转换数据类型
     if(ret<0)
     {
         close(sockefd);
         MY_PRINTF("bind err !! ");
         return -1;
     }
     MY_PRINTF("bind ok !! ");


     ret=listen(sockefd,5);//监听
     if(ret<0)
     {
         close(sockefd);
         MY_PRINTF("listen err !! ");
         return -1;
     }
     MY_PRINTF("listen ok !! ");


     sockenewfd=accept(sockefd,(struct sockaddr *)&remote_addr,&remote_addr_len);//获取连接的新套接字
     if(sockenewfd<0)
     {
         close(sockefd);
         MY_PRINTF("accept err !! ");
         return -1;
     }
     MY_PRINTF("accept ok !! ");


    printf("%d\r\n",ntohs(remote_addr.sin_port));  //端口号
    printf("%s\r\n",inet_ntoa(remote_addr.sin_addr));//ip地址    //转换为字符串形式以 数字.数字.数字.数字 的格式显 示出来


     for(;;)
     {
            ret=recv(sockenewfd,buf,sizeof(buf),0);//接收
            if(ret<0)
            {
                close(sockenewfd);
                MY_PRINTF("recv err !! ");
                break;
            }
            else if(ret==0)
            {
                close(sockenewfd);
                MY_PRINTF("close !! ");
                perror("close sockenewfd");  
                break;
            }
            MY_PRINTF("recv ok !! ");
            MY_PRINTF(buf);


            ret=send(sockenewfd,buf,ret,0);//发送 等价于write(sockenewfd,buf,ret);
            if(ret<0)
            {
                MY_PRINTF("send err !! ");
            }
            MY_PRINTF("send ok !! ");
            MY_PRINTF(buf);
     }




      close(sockefd);//关闭
      perror("close sockefd");
      return0;


 }

程序运行只允许单个客户端连接通讯。测试如下:

服务端启动,等待连接,如下:

Linux 网络编程 tcp server 笔记_第2张图片

客户端连接,如下:

Linux 网络编程 tcp server 笔记_第3张图片

服务端获取到客户端连接,如下:

Linux 网络编程 tcp server 笔记_第4张图片

客户端发送数据,并接收到服务端返回,如下:

Linux 网络编程 tcp server 笔记_第5张图片

服务端显示:

Linux 网络编程 tcp server 笔记_第6张图片

三、服务器-多客户端

这里介绍两种方法,方法一:使用多线程;方法二:使用select方法。

①方法一多线程,测试代码如下:

#include 
#include 
#include 
#include 
#include  //struct sockaddr_in
#include  //inet_addr()
#include //close()




#define MY_PRINTF(argv)   do{\
                                printf("file:%s --- function:%s --- line:%d\r\n",__FILE__,__FUNCTION__,__LINE__);\
                                printf("%s\r\n",argv);\
                            }while(0);
#define MYPORT 5000
//tcp server demo




void *myfun_thread(void *socketInfo)
{
    char buf[1024];
     int ret;
    int sockenewfd=(int)socketInfo;


     for(;;)
     {
            ret=recv(sockenewfd,buf,sizeof(buf),0);//接收
            if(ret<0)
            {
                  close(sockenewfd);
                MY_PRINTF("recv err !! ");
                perror("close sockenewfd");  
                break;
            }
            else if(ret==0)
            {
                close(sockenewfd);
                MY_PRINTF("close !! ");
                perror("close sockenewfd");  
                break;
            }
            MY_PRINTF("recv ok !! ");
            MY_PRINTF(buf);


            ret=send(sockenewfd,buf,ret,0);//发送 等价于write(sockenewfd,buf,ret);
            if(ret<0)
            {
                MY_PRINTF("send err !! ");
            }
            MY_PRINTF("send ok !! ");
            MY_PRINTF(buf);
     }
     pthread_exit(NULL);


}


 int main(int argc,char *argv[])
{
     int sockefd;
     int sockenewfd;
     int ret;
     int enable=1;
     pthread_t  threadRx;
     struct sockaddr_in my_addr;//本地地址-服务器


     struct sockaddr_in remote_addr;//远端地址-客户端
     int remote_addr_len;


     


     sockefd=socket(AF_INET,SOCK_STREAM,0);// 套接字
     if(sockefd<0)
     {
         MY_PRINTF("socket err !! ");
         return -1;
     }
     if (setsockopt(sockefd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(enable)) == -1) 
     {
        close(sockefd);
        MY_PRINTF(" setsockopt  err !! ");
        return -1;
    }
     MY_PRINTF("socket ok !! ");


     //本地地址
     my_addr.sin_family=AF_INET;    
     my_addr.sin_port=htons(MYPORT);//0:随机端口
     my_addr.sin_addr.s_addr=INADDR_ANY;//inet_addr("192.168.164.157");//INADDR_ANY:本机 ip  // inet_addr():IP 地址的字符串转换成一个无符号长整型
     bzero(my_addr.sin_zero,sizeof(my_addr.sin_zero));


    
     ret=bind(sockefd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));//绑定   //转换数据类型
     if(ret<0)
     {
         close(sockefd);
         MY_PRINTF("bind err !! ");
         return -1;
     }
     MY_PRINTF("bind ok !! ");


     ret=listen(sockefd,5);//监听
     if(ret<0)
     {
         close(sockefd);
         MY_PRINTF("listen err !! ");
         return -1;
     }
     MY_PRINTF("listen ok !! ");


     while(1)
     {
                sockenewfd=accept(sockefd,(struct sockaddr *)&remote_addr,&remote_addr_len);//获取连接的新套接字
                if(sockenewfd<0)
                {
                    MY_PRINTF("accept err !! ");
                    break;
                }
                MY_PRINTF("accept ok !! ");


                printf("%d\r\n",ntohs(remote_addr.sin_port));  //端口号
                printf("%s\r\n",inet_ntoa(remote_addr.sin_addr));//ip地址    //转换为字符串形式以 数字.数字.数字.数字 的格式显 示出来
                pthread_create(&threadRx, NULL, myfun_thread, (void *)sockenewfd);
                sleep(1);
     }
     close(sockefd);//关闭
    perror("close sockefd");  
     return 0;


 }

测试结果:

服务端:

Linux 网络编程 tcp server 笔记_第7张图片

客户端:

Linux 网络编程 tcp server 笔记_第8张图片

你可能感兴趣的:(网络,linux,tcp/ip,笔记,运维)