linux网络编程----套接字编程

源代码在github上点击这里

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节

套接字:IP地址 + TCP端口号
(socket) 一个套接字,唯一标识网络通讯中的一个进程
TCP/IP协议中,两个进程若想建立连接,就离不开套接字,它是TCP连接中的端点

套接字地址结构:(用来保存套接字的相应信息)

linux下

IPv4套接字地址结构

IPv4套接字地址结构通常也叫做“网际套接字地址结构”,以sockaddr_in命名:定义在<netinet/in.h>
   struct in_addr
     {
          in_addr_t s_addr;  /*32位IP地址*/
     };

     struct sockaddr_in
     {
          short sin_family;                 /*Address family一般来说AF_INET(地址
                                              族)PF_INET(协议族)*/
          unsigned short sin_port;          /*Port number(必须要采用网络数据格式,普
                                            通数字可以用htons()函数转换成网络数据格式的数字)*/
          struct in_addr sin_addr;          /*IP address in network byte
                                           order(Internet address)*/
          unsigned char sin_zero[8];        /*Same size as struct sockaddr没有实
                                              际意义,只是为了 跟SOCKADDR结构在内存中
                                              对齐,是为了让sockaddr与sockaddr_in
                                              两个数据结构保持大小相同而保留的空字节。*/
     };

通用套接字地址结构:不建立该类型的结构体变量,而只是在传参的时候,进行强制类型转换成该类型,
和void*类型一样,为了函数支持各种类型的数据

struct sockaddr               
{
     unsigned  short  sa_family;        /* address family, AF_xxx */
     char  sa_data[14];                 /* 14 bytes of protocol address */
};

     AF_前缀代表地址族,PF_前缀代表协议族
     sa_family是地址家族,一般都是“AF_xxx”的形式。好像通常大多用的是都是AF_INET。
     sa_data是14字节协议地址。

     此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。
     但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构,如sockaddr_in,sockaddr_un,sockaddr_in6...

套接字地址结构体使用方式 :

IPv4地址用sockaddr_in结构体表示,IPv6地址用sockaddr_in6结构体表示,UNIX Domain
Socket地址用sockaddr_un结构体表示,为了让socket API可以接受各种类型的sockaddr结构体
指针做参数,例如bind,accept,connect等函数,这些函数的参数应该设置为void* 类型的指
针,但socket API的实现早于ANSI C标准化,那个时候还没有void* 类型,因此这些函数的参数
都用struct sockaddr* 类型表示,所以struct sockaddr*是一个通用类型指针。在传递参数之前
要强制类型转换:如
struct sockaddr_in servaddr;
bind(sock_fd,(struct sockaddr *)&servaddr,sizeof(servaddr));

建立TCP连接所用函数解析:

1.socket();
      函数原型:  int socket(int domain,int type,int protocol);
      作用 :socket函数是一种可用于根据指定的地址族、数据类型和协议来分配一个套接口的描述
      字及其所用的资源的函数
      参数:
           domain:  一个地址描述。目前仅支持AF_xxxx格式:AF_INET代表IPv4地址
           type:       新套接字的类型描述:SOCK_STREAM  : 提供面向连接的稳定数据传
           输,即TCP协议。 SOCK_dGRAM:表示面向数据报的传输协议,即UDP协议
           protocol :    套接字所用的协议。如调用者不想指定,可用0指定,表示缺省。
      返回值:
          成功返回文件描述符>0,失败返回<0,
2.bind()
     函数原型:int bind(int sockfd, const struct sockaddr *addr,  socklen_t addrlen);
     作用: 绑定服务器ip地址和端口,因为服务器程序所监听的网络地址和端口号通常是固定不变
     的,将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描
     述的地址和端口号
     参数:
               sockfd:socket创建成功的返回值
               addr :存有套接字信息的结构体的地址(注意强制类型转换)
               addrlen: 前一个套接字结构体类型的变量的长度:addr参数可以接受多种协议的
               sockaddr结构体,而它们的长度各不相同,所以需要第三个addrlen指定结构体的长度。
     返回值:
                    成功返回0,失败返回-1
3.  listen():
         函数原型:int listen(int sockfd,int backlog);
         作用:仅被TCP服务器调用,声明sockfd处于监听状态,并且最多有backlog个客户端处于
         连接等待状态,
         返回值:成功返回0,失败返回-1
4.accept():
           函数原型:int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen)
           作用:用于接收客户端的连接请求
           参数:
                    sockfd:称为监听套接字,即服务器的套接字,也是其文件描述符
                    addr : 客户端的套接字地址结构体的变量的地址
                    addrlen:传入传出型参数,传入的是调用者提供的缓冲区的长度,以避免缓
                    冲区溢出,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提
                    供的缓冲区)
           返回值:
                 成功返回客户端的IP地址和端口号(即套接字),失败返回-1
5.网络字节序和主机字节序的转换:(为使网络程序具有可移植性,使同样的代码在大端小端机器都可
编译正常运行,对应于开篇的首句话)

       #include <arpa/inet.h>

       uint32_t htonl(uint32_t hostlong);
       uint16_t htons(uint16_t hostshort);
       uint32_t ntohl(uint32_t netlong);
       uint16_t ntohs(uint16_t netshort);

     h表示host,n表示network,l表示32位长整数(IP地址),s表示16为短整数(端口号);
     例如:htonl表示将32位的长整数从主机字节序转换为网络字节序,即:将IP地址转换后准备发
     送,若主机是小端字节序,这些函数将参数做相应的大小端转换后返回,若是大端字节序,这些函
     数不做转换,将参数原封不动的返回
6.字符串转in_addr的函数:

        int inet_aton(const char *strptr, struct in_addr *addrptr);
        in_addr_t inet_addr(const char *strptr);
        int inet_pton(int family,const char* strptr,void *addrptr);
7.in_addr转字符串的函数:

       char *inet_ntoa(struct in_addr inaddr);
       const char *inet_ntop(int family,const void* addrptr,char* strptr,size_t len);

      其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr,因
      此函数接口是void *addrptr
8. connect():
     函数原型:int connect (int sockfd,const struct sockaddr *addr,socklen_t addrlen)
     作用:客户端调用connect连接服务器
     参数:其参数形式和bind一致,区别在于bind的参数是自己的地址,而connect参数是对方的地址。
     返回值:
          成功返回0,失败返回-1.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
网络编程在 ARM-Linux 上与在其他平台上的网络编程基本相同,在 ARM-Linux 上使用的套接字函数库也是基于 BSD Socket 的。下面是一个简单的网络编程实验,可以在 ARM-Linux 上运行。 首先,需要创建一个 TCP 服务器,可以使用以下代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8080 int main() { int server_fd, new_socket, valread; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); char buffer[1024] = {0}; char *hello = "Hello from server"; // Creating socket file descriptor if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // Forcefully attaching socket to the port 8080 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons( PORT ); // Forcefully attaching socket to the port 8080 if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) { perror("bind failed"); exit(EXIT_FAILURE); } if (listen(server_fd, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) { perror("accept"); exit(EXIT_FAILURE); } valread = read( new_socket , buffer, 1024); printf("%s\n",buffer ); send(new_socket , hello , strlen(hello) , 0 ); printf("Hello message sent\n"); return 0; } ``` 这个程序创建了一个 TCP 服务器并绑定到 8080 端口。当客户端连接到服务器时,服务器会发送“Hello from server”字符串,然后关闭连接。 接下来,需要创建一个 TCP 客户端,可以使用以下代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8080 int main(int argc, char const *argv[]) { int sock = 0, valread; struct sockaddr_in serv_addr; char *hello = "Hello from client"; char buffer[1024] = {0}; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("\n Socket creation error \n"); return -1; } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); // Convert IPv4 and IPv6 addresses from text to binary form if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) { printf("\nInvalid address/ Address not supported \n"); return -1; } if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { printf("\nConnection Failed \n"); return -1; } send(sock , hello , strlen(hello) , 0 ); printf("Hello message sent\n"); valread = read( sock , buffer, 1024); printf("%s\n",buffer ); return 0; } ``` 这个程序创建了一个 TCP 客户端并连接到 127.0.0.1 的 8080 端口。它发送“Hello from client”字符串,然后等待服务器的响应。 可以使用以下命令编译和运行这两个程序: ```bash arm-linux-gcc -o server server.c arm-linux-gcc -o client client.c ``` ```bash ./server & ./client ``` 这些程序应该能够在 ARM-Linux 上运行,并且客户端应该能够接收到服务器发送的“Hello from server”字符串。这个实验展示了如何在 ARM-Linux 上进行基本的网络编程

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值