欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

嵌入式Linux 网络编程

程序员文章站 2022-04-17 14:10:24
涉及到的数据结构: 下面首先介绍两个重要的数据类型:sockaddr和sockaddr_in,这两个结构类型都是用来保存socket地址信息的 定义如下所示: 这两个数据类型是等效的,可以相互转化,通常sockaddr_in数据类型使用更为方便。在建立socketaddr或sockaddr_in后, ......

 

涉及到的数据结构:

  下面首先介绍两个重要的数据类型:sockaddr和sockaddr_in,这两个结构类型都是用来保存socket地址信息的

定义如下所示:

struct sockaddr {
    unsigned short sa_family; /*地址族*/
    char sa_data[14];     /*14字节的协议地址,包含该socket的IP地址和端口号*/
};
struct sockaddr_in {
    short int sa_family;             /*地址族*/
    unsigned short int sin_port; /*端口号*/
    struct in_addr sin_addr;     /*IP地址*/
    unsigned char sin_zero[8]; /*填充0 以保持与struct sockaddr同样大小*/
};            

  这两个数据类型是等效的,可以相互转化,通常sockaddr_in数据类型使用更为方便。在建立socketaddr或sockaddr_in后,就可以对该socket进行适当的操作了。
  如表所示列出了该结构sa_family字段可选的常见值:

嵌入式Linux 网络编程

 

涉及到的函数:

1. socket函数:创建套接字

 socket函数标准调用格式说明如下:

#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol);  //成功返回一个正整数,失败返回-1
  • domain: 套接字的协议族,如:AF_INET(IPv4协议)、AF_INET6(IPv6协议)、AF_UNIX、AF_LOCAL(本地交互协议)等等
  • type: 指定当前的套接字类型,如:SOCK_STREAM(数据流)、SOCK_DGRAM(数据报)、SOCK_RAW(原始套接字)等等
  • protocol: 在使用原始套接字之外通常设置为0,表示使用默认协议

 

2. bind函数:绑定套接字

 bind函数标准调用格式说明如下:

#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, const struct socketaddr *addr, socklen_t addrlen);  //成功返回0,否则返回-1
  • sockfd: 使用socket函数创建的套接字对应的套接字描述符
  • addr: 本地地址
  • addrlen: 套接字对应的地址结构长度

 

3. connect函数:建立连接

 connect函数标准调用格式说明如下:

#include <sys/types.h>
#include <sys/socket.h>

int connect(int sockfd, const struct socketaddr *addr, socklen_t addrlen);  //成功返回0,否则返回-1
  • sockfd: 使用socket函数创建的套接字对应的套接字描述符
  • addr: 指定远程服务器的套接字地址,包括服务器的IP地址和端口号
  • addrlen: 该套接字对应的地址结构长度

 

4. listen函数:倾听模式

 listen函数标准调用格式说明如下:

#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd, int backlog);  //成功返回0,否则返回-1
  • sockfd: 使用socket函数创建的套接字对应的套接字描述符
  • backlog: 设置请求队列的最大长度

 

5. accept函数:接收连接

 accept函数标准调用格式说明如下:

#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd, struct socketaddr *addr, socklen_t *addrlen);  
  • sockfd: 使用socket函数创建的套接字对应的套接字描述符
  • addr: 指向一个Internet套接字地址结构的指针
  • addrlen: 指向一个整型变量的指针

 

6. close函数:关闭连接

 close函数标准调用格式说明如下:

#include <unistd.h>

int close(int fd); 

 

7. send和recv函数:发送和接收数据

 send和recv函数标准调用格式说明如下:

#include <sys/types.h>
#include <sys/socket.h>

ssize_t send(int sockfd, const void  *buf, size_t len, int flags);  //成功返回实际发送的字节数,否则返回-1
ssize_t recv(int sockfd, void *buf, size_t len, int flags);      //成功返回实际接收的字节数,否则返回-1
  • sockfd: 使用socket函数创建的套接字对应的套接字描述符
  • buf: 待发送或接收数据的缓存区
  • len: 待发送数据的缓存区的长度或接收数据的长度
  • flags: 用于指定消息的传送类型

 

【应用实例】 ——   Linux 系统 TCP网络协议编程

  通过一个简单的 tcp 服务器端,接收客户端的连接请求,并接受客户端发来的信息。

  服务器端和客户端使用TCP协议的流程图如图:

  嵌入式Linux 网络编程

图 - 使用TCP协议socket编程流程图

  其中服务器端首先建立起socket,然后调用本地端口的绑定,接着就开始与客户端建立联系,并接收客户端发送的消息。客户端则在建立socket之后调用connect函数来建立连接。

服务器端的源代码如下所示:

// server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <string.h>

#define PORT 5555	//服务器接听端口号
#define BUF_SIZE 1024	//缓存区大小

int main(int argc, char *argv[])
{
	int ret;
	char buf[BUF_SIZE];
	int sockfd;
	int clientfd;
	struct sockaddr_in addr;
	struct sockaddr_in client_addr;
	int length = sizeof(client_addr);
	
	//创建套接字
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if( sockfd == -1 )
	{
		printf("socket fail...");
		return 1;
	}
	//绑定套接字
	bzero(&addr, sizeof(struct sockaddr));
	addr.sin_family = AF_INET;			//IPv4
	addr.sin_port = htons(PORT);			//设定端口号
	addr.sin_addr.s_addr = htonl(INADDR_ANY);	//本地IP地址
	ret = bind(sockfd, (struct sockaddr*)(&addr), sizeof(struct sockaddr));
	if( ret == -1 )
	{
		printf("bind fail...");
		return 1;
	}
	//监听网络端口
	ret = listen(sockfd, 5);
	if(ret == -1)
	{
		printf("listen fail...");
		return 1;
	}
	while(1)
	{
		//接收连接请求
		clientfd = accept(sockfd, (struct sockaddr*)(&client_addr), &length);
		if(clientfd == -1)
		{
			printf("accept fail...");
			return 1;
		}
		
		while(1)
		{
			bzero(buf, sizeof(buf));	//清空缓存区
			//接收数据
			recv(clientfd, buf, sizeof(buf), 0);	
			printf("recv: %s\n", buf);
			sleep(2);
		}
		close(clientfd);
	}
	return 0;
}

 

客户端的源代码如下所示:

// client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <string.h>

#define PORT 5555
#define BUF_SIZE 1024

int main(int argc, char *argv[])
{
	int ret;
	char buf[BUF_SIZE];
	int sockfd;
	struct sockaddr_in addr;
	
	//创建套接字
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if( sockfd == -1 )
	{
		printf("socket fail...");
		return 1;
	}
	//建立连接
	bzero(&addr, sizeof(struct sockaddr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);	//使用回环地址 127.0.0.1
	ret = connect(sockfd, (struct sockaddr*)(&addr), sizeof(struct sockaddr));
	if( ret == -1 )
	{
		printf("connect fail...");
		return 1;
	}
	
	while(1)
	{
		bzero(buf, sizeof(buf));
		printf("send: ");
		scanf("%s", buf);
		send(sockfd, buf, strlen(buf), 0);	//发送数据
		sleep(1);
	}
	
	close(sockfd);
	return 0;
}