• 套接字编程基础


     

    套接字是通信断点的抽象,网络编程中,套接字对于大多数通信细节做了隐藏,使程序员操作起来比较简单。

    1、建立和销毁套接字描述符

    Linux环境中使用socket函数创建一个套接字,函数原型如下:

    int socket(int domain,int type,int protocol);

    头文件:  #include<sys/types.h>、#include<sys/socket.h> 

    参数说明:

    第一个参数domain是通信域,“AF_INET”表示IPv4,“AF_INET6”表示IPv6。

    第二个参数是套接口的类型,SOCK_STREAM表示是TCP协议,SOCK_DGRAM表示是UDP协议,SOCK_RAW表示是绕过协议,SOCK_SEQPACKET表示STCP协议。

    第三个参数通常设置为0。

    返回值:系统调用socket()只返回一个套接口描述符,如果出错,则返回-1。

    2、地址绑定

    只有绑定了地址的套接字才能用于网络通信,因此需要将套接字与一个地址绑定,Linux环境下使用bind()函数将一个套接字绑定到一个地址上,函数如下:

    int bind(int sockfd,struct sockaddr*my_addr,int addrlen);

    头文件:#include<sys/types.h>、#include<sys/socket.h>

    参数说明:

    第一个参数sockfd是由socket()调用返回的套接口文件描述符。

    第二个参数my_addr是指向数据结构sockaddr的指针。数据结构sockaddr中包括了关于你的地址、端口和IP地址的信息。

    第三个参数addrlen可以设置成sizeof(structsockaddr)。

    返回值:如果绑定成功函数返回0,失败返回-1。

    3、建立一个连接

    套接字与地址绑定之后,就可以建立一个连接,在Linux环境下使用connect函数主动建立一个连接,函数原型如下:

    int connect(int sockfd,struct sockaddr* serv_addr,int addrlen);

    头文件:#include<sys/types.h>、#include<sys/socket.h>

    参数说明:

    第一个参数还是套接口文件描述符,它是由系统调用socket()返回的。

    第二个参数是serv_addr是指向数据结构sockaddr的指针,其中包括目的端口和IP地址。

    第三个参数可以使用sizeof(structsockaddr)而获得。

    返回值:如果建立连接成功函数返回0,失败返回-1。

    客户端主动建立连接,服务器端接受连接。服务器端接受连接分为两步,第一步,创立一个套接字监听连接请求,第二步,创立一个新的套接字接受并且处理请求。Linux环境中使用listen函数监听连接请求,函数如下:

    intl isten(int sockfd,int backlog);

    头文件:#include<sys/socket.h>

    参数说明:

    第一个参数是用来进行连接请求监听的套接字描述符。

    第二个参数表示最多可以排队等待连接的请求数量。

    返回值:成功返回0,失败返回-1。

    调用listen函数之后,该套接字就可以开始监听请求了,接受连接请求使用accept函数,函数如下:

    intaccept(intsockfd,void*addr,int*addrlen);

    头文件:#include<sys/socket.h>

    参数说明:

    第一个参数是正在监听端口的套接口文件描述符。

    第二个参数是一个地址结构,改地址往往是客户端的地址,一般设置为NULL。

    第三个参数表示取得的客户端地址的大小,这个值要小于用户提供的缓冲区大小。如果忽略改地址,设置为NULL.

    返回值:成功返回0,失败返回-1。

    应用实例:

    服务器端程序

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <strings.h>
    #include <ctype.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #define MAX_LINE 100
     
    /*处理函数,用于将大写字符转换成小写字符。参数为需要转换的字符串*/
    void my_fun(char *p)
    {
           if(p == NULL)
                  return ;
           for(; *p != ''; p++)
                  if(*p >= 'A' && *p <= 'Z')
                         *p = *p - 'A' + 'a';
    }
     
    int main(void)
    {
           struct sockaddr_in sin;
           struct sockaddr_in cin;
           int l_fd;
           int c_fd;
           socklen_t len;
           char buf[MAX_LINE];                         ///存储传送内容的缓存
           char addr_p[INET_ADDRSTRLEN];      ///存储客户端地址的缓冲区
           int port = 8000;                          ///端口号,使用8000
           int n;                                                 ///读写字节数
           bzero(&sin, sizeof(sin));        ///清空地址空间
           sin.sin_family = AF_INET;            ///使用IPv4通信域
           sin.sin_addr.s_addr = INADDR_ANY;///服务器可以接受任意地址
           sin.sin_port = htons(port);           ///端口号转换为网络字节序
           /*创立套接字,使用TCP协议*/
           l_fd = socket(AF_INET, SOCK_STREAM, 0);
           /*将地址和套接字绑定*/
           bind(l_fd, (struct sockaddr*)&sin, sizeof(sin));
           /*开始监听链接请求*/
           listen(l_fd, 10);
           printf("waiting ...
    ");
           /*服务器程序多半是死讯环
            * 接受链接请求,函数中返回后就可以开始通信了
            * */
           while(1)
           {
                  c_fd = accept(l_fd, (struct sockaddr*)&cin, &len);
                  n = read(c_fd, buf, MAX_LINE);
                  inet_ntop(AF_INET, &cin.sin_addr, addr_p, sizeof(addr_p));
                  printf("client IP is %s, port is %d
    ", addr_p, ntohs(cin.sin_port));
                  printf("content is : %s
    ", buf);
                  my_fun(buf);
                  write(c_fd, buf, n);
                  close(c_fd);
           }
           return 0;
    }

    客户端程序:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <strings.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #define MAX_LINE 100
     
    int main(int argc, char *argv[])
    {
           struct sockaddr_in sin;
           char buf[MAX_LINE];
           int sfd;
           int port = 8000;
           char *str = "test sting";
           if(argc > 1)
           {
                  str = argv[1];
           }
           bzero(&sin, sizeof(sin));
           sin.sin_family = AF_INET;   ///使用IPv4地址族
          
           /*和本机通信,同一台主机担任服务器和客户端的角色*/
           inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);
           sin.sin_port = htons(port);
           sfd = socket(AF_INET, SOCK_STREAM, 0);
           connect(sfd, (const struct sockaddr *)&sin, sizeof(sin));
           write(sfd, str, strlen(str) + 1);
           read(sfd, buf, MAX_LINE);
           printf("receive from serev : %s
    ", buf);
           close(sfd);
           return 0;
    }
  • 相关阅读:
    Python笔记-面向对象编程
    大学课后答案微信小程序项目实践(1)
    用weexplus从0到1写一个app(2)-页面跳转和文章列表及文章详情的编写
    react基础学习和react服务端渲染框架next.js踩坑
    基于weex的app开发脚手架weexplus学习笔记
    用weexplus从0到1写一个app
    Vue与React两个框架的区别对比
    mpvue学习笔记-之微信小程序数据请求封装
    Flutter/Dart import导入文件关键字总结
    55个提高你CSS开发效率的必备片段(转自:前段日刊)
  • 原文地址:https://www.cnblogs.com/Mr--Yang/p/6686910.html
Copyright © 2020-2023  润新知