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。

  • 相关阅读:
    字典转模型
    iOS开发之---传值大全
    UITableViewCell重用机制
    通知/代理/block 三者比对
    内存的那些事
    C++
    C#接口实现案例
    4.2 C#-----------------------------操作符的重载------------------------------------------
    C#抽象类和抽象方法的实现
    C#----析构函数
  • 原文地址:https://www.cnblogs.com/codercql/p/13052609.html
Copyright © 2011-2022 走看看