zoukankan      html  css  js  c++  java
  • Socket网络编程

    Socket——进程间(远程)通信的一种机制。

    套接字(Socket):IP地址与端口号的组合。

      两方进行通信时,必须要知道对方主机的IP地址和进程的端口号。

      在 Linux 中的网络编程是通过 socket 接口来进行的。套接字(socket)是一种特殊的 I/O 接口,它也是一种文件描述符。socket 也有一个类似于打开文件的函数调用,该函数返回一个整型的 socket 描述符,随后的连接建立、数据传输等操作都是通过 socket 来实现的。

      套接字可分为3种类型:

      (1)字节流Socket(Stream Socket):基于TCP,提供可靠的字节流传输;

      (2)数据报Socket(Datagram Socket):基于UDP,提供不可靠的报文传输;

      (3)原始套接字 Raw Socket:基于IP,允许用户直接对IP操作;

     

    Socket操作的常用系统调用:

    • socket():建立Socket端点,获得Socket描述符
    • bind():Server绑定Socket地址(IP地址+端口号)
    • listen():Server等待Client连接,是一个阻塞操作
    • connect():Client连接到Server
    • accept():Server获得连接请求的 Client的Socket地址
    • send()、recv():在已建立的连接上发送、接收数据(TCP方式)
    • sendto()、recvfrom():无需连接,直接发送、接收数据(UDP方式)
    • close():关闭Socket(单向/双向)

    基于TCP的Socket程序流程:

      

    具体步骤:

    1. 创建服务端socket,绑定建立连接的端口。
    2. 服务端程序在一个端口调用监听后,处于阻塞状态,等待客户机的连接。
    3. 创建客户端socket对象。
    4. 客户端指定主机名称或IP地址、连接端口号。
    5. 客户机socket发起连接请求。
    6. 建立连接。
    7. 利用send()和recv()进行数据传输。
    8. 关闭socket。

    server.c

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <netinet/in.h>
    int main()
    {
        int sockfd,new_fd,numbytes;
        struct sockaddr_in my_addr;
        struct sockaddr_in their_addr;
        int sin_size;
        char buff[100];
        //服务器创建socket套接字描述符
        if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
        {
            perror("socket!");
            exit(1);
        }
        printf("socket Success!,sockfd=%d
    ",sockfd);
        //初始化sockaddr结构体,设置绑定4321端口
        my_addr.sin_family=AF_INET;
        my_addr.sin_port=htons(4321);//数据格式转换
        my_addr.sin_addr.s_addr=INADDR_ANY;//本机地址
        bzero(&(my_addr.sin_zero),8);
        //绑定套接字描述符sockfd
        if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==-1)
        {
            perror("bind");
            exit(1);
        }
        printf("bind Success!
    ");
        //创建监听套接字
        if(listen(sockfd,10)==-1)
        {
            perror("listen");
            exit(1);
        }
        printf("Listen.....
    ");
        //服务器阻塞监听套接字,等待客户端连接
        while(1)
        {
            sin_size=sizeof(struct sockaddr_in);
            //如果建立连接,产生新套接字,用于与客户端通信
            if((new_fd = accept(sockfd,(struct sockaddr *)&their_addr,&sin_size))==-1)
            {
                perror("accept");
                exit(1);
            }
            //生成一个子进程来进行会话,父进程继续监听
            if(!fork())
            {
                //读取客户端发来的信息
                if((numbytes = recv(new_fd,buff,60,0))==-1)
                {
                    perror("recv");
                    exit(1);
                }
                printf("%s
    ",buff);
                //发送信息到客户端
                if(send(new_fd,"Welcome ,This is server.",60,0)==-1)
                    perror("send");
                //本次通信结束
                close(new_fd);
                exit(0);
            }
            //
        }
        close(sockfd);
        return 0;
    }

    client.c

    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <stdlib.h>
    #include <netdb.h>
    #include <netinet/in.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    int main(int argc ,char * argv[])//命令行传递地址
    {
        int sockfd,numbytes;
        char buff[100];
        struct hostent * he;
        struct sockaddr_in their_addr;
        int i=0;
        //命令行中的第二个参数为服务器IP
        he=gethostbyname(argv[1]);
        //客户端建立socket套接字描述符
        if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
        {
            perror("socket!");
            exit(1);
        }
        //printf("socket Success!,sockfd=%d
    ",sockfd);
        their_addr.sin_family=AF_INET;
        their_addr.sin_port=htons(4321);
        their_addr.sin_addr=*((struct in_addr *)he->h_addr);
        bzero(&(their_addr.sin_zero),8);
        //向服务器发起连接
        if(connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr))==-1)
        {
            perror("connect");
            exit(1);
        }
        //向服务器发送字符串
        if(send(sockfd,"hello!I am client.",26,0)==-1)
        {
            perror("send");
            exit(1);
        }
        //接收从服务器返回的信息
        if((numbytes = recv(sockfd,buff,100,0))==-1)
        {
            perror("recv");
            exit(1);
        }
        printf("recv is :%s
    ",buff);
        //通信结束
        close(sockfd);
        return 0;
    }

     创建一个Web程序:

    #include<stdio.h>-
    #include<pthread.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    
    int KEY_QUIT =0;
    char referrer[128];
    int content_length;
    #define SERVER_PORT 80
    static char copybuf[16384];
    //复制一个word文档副本
    int copy(FILE * read_f ,FILE * write_f)
    {
        int n;
        int wrote;
        n=fread(copybuf ,1,sizeof(copybuf),read_f);
        wrote=fwrite(copybuf,n,1,write_f);
        return 0;
    }
    //发送HTML文件内容
    int DoHTML(FILE * f ,char * name)
    {
        char * buf;
        FILE * infile;
        infile=fopen(name,"r");
        copy(infile,f);
        fclose(infile);
        return 0;
    }
    //解析客户需求
    int ParseReq(FILE * f ,char * r)
    {
        char * bp;
        char * c;
    #ifdef BEBUG
        printf("req is %s
    ",r);
    #endif
    while(*(++r)!=' ');
    //判断是否为空白符(空格、换页、回车、制表符等)
    while(isspace(*r)) r++;
    while(*r=='/') r++;
    bp=r;
    while(*r &&(*(r)!=' ')&&(*(r)!='?'))
        r++;
    *r=0;
    c=bp;
    DoHTML(f,c);
    return 0;
    }
    //客户连接处理
    int HandleConnect(int fd)
    {
        FILE *f;
        char buf[160];
        f=fdopen(fd,"a+");
        setbuf(f,0);
        fgets(buf,150,f);
    #ifdef DEBUG
        printf("buf=%s
    ",buf);
    #endif
        ParseReq(f,buf);
        fflush(f);
        fclose(f);
        return 1;
    }
    //按Q键退出服务程序
    void * Key_in(void * data)
    {
        int c;
        for(;;)
        {
            c=getchar();
            if(c=='q'||c=='Q')
            {   KEY_QUIT=1;
                exit(10);
                break;
            }
        }
    }
    int main(int argc, char * argv[])
    {
        int fd,sockfd;
        int len;
        volatile int true=1;
        struct sockaddr_in ec;
        struct sockaddr_in server_sockaddr;
        pthread_t th_key;
        printf("starting httpd...
    ");
        printf("press q to quit
    ");
        //建立socket套接字
        sockfd =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        setsockopt(sockfd,SOL_SOCKET, SO_REUSEADDR, (void *)&true ,sizeof(true));
    
        server_sockaddr.sin_family =AF_INET;
        server_sockaddr.sin_port=htons(SERVER_PORT);
        server_sockaddr.sin_addr.s_addr=htonl(INADDR_ANY);
        //把套接字socket与地址、端口号绑在一起
        bind(sockfd,(struct sockaddr *)&server_sockaddr,
                sizeof(server_sockaddr));
        //设置监听
        listen(sockfd,8*3);
    //按Q键退出程序
    //pthread_create(&th_key,NULL,Key_in,NULL); //等待客户端连接请求 printf("waitting for connection... "); while(1) { len=sizeof(ec); if((fd=accept(sockfd,(void *)&ec,&len))==-1) { exit(5); close(sockfd); } HandleConnect(fd); } }

    然后再写一个网页脚本文件index.html。程序编译运行后,打开浏览器:http://IP地址/index.html。

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    现在使用控件, 更喜欢继承(覆盖控件已有的函数,很奇怪的一种使用方式)
    Controls 属性与继承 TShape 类的小练习(使用TShape可以解决很多图形问题)
    QT创建窗口程序、消息循环和WinMain函数(为主线程建立了一个QEventLoop,并执行exec函数)
  • 原文地址:https://www.cnblogs.com/codercql/p/13052609.html
Copyright © 2011-2022 走看看