嵌入式Linux(二):Socket 通信

前言

嵌入式Linux实现TCP或UDP通信是使用Socket编程来实现。本文主要记录实现TCP UDP的细节。

(一):Socket编程相关函数

通过man命令可以查看相关函数的文档。

1.socket

socket可以返回一个socket一个endpoint用于通信,并返回一个整型用于描述这个endpoint,错误返回-1.

# man socket
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

//实例
iSocketServer = socket(AF_INET,SOCK_STREAM, 0);

1.1 domain:

   Name                Purpose                          Man page
   AF_UNIX, AF_LOCAL   Local communication              unix(7)
   AF_INET             IPv4 Internet protocols          ip(7)
   AF_INET6            IPv6 Internet protocols          ipv6(7)

1.2 type(详细可看man socket)

SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission
mechanism may be supported.
SOCK_DGRAM Supports datagrams (connectionless, unreliable messages of a fixed maximum length).

1.3 protocol (一般直接取0)

The protocol specifies a particular protocol to be used with the socket.  Normally only a single protocol exists to support a particular socket type within a given protocol family, in which case protocol can be specified as 0.

2.bind

该函数用于给socket绑定IP地址。
#include <sys/types.h>         
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

//实例
struct sockaddr_in tSocketServerAddr;
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port   = htons(SEVEER_PORT); //htons host to net short
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;    //接收任何IP
memset(tSocketServerAddr.sin_zero, 0, 8);          //置零

iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr,sizeof(struct sockaddr));
if (iRet==-1){
        printf("bind error!\n");
        return -1;
    }

2.1 sockfd

socket函数返回标识socket的整数。
sockfd = socket(AF_INET,SOCK_STREAM, 0);

2.2 addr

改参数的输入的是

struct sockaddr {
       		sa_family_t sa_family;
       		char        sa_data[14];
           }

但一般用struct sockaddr_in:

sockaddr_in在头文件#include<netinet/in.h>或#include <arpa/inet.h>中定义,该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中

#include <arpa/inet.h>

struct sockaddr_in tSocketServerAddr;
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port   = htons(SEVEER_PORT); //htons host to net short
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;    //接收任何IP
memset(tSocketServerAddr.sin_zero, 0, 8);          //置零

iRet = bind(sockfd, (const struct sockaddr *)&tSocketServerAddr,sizeof(struct sockaddr));

2.3 addrlen

前面地址的大小。
sizeof(struct sockaddr)

2.4 返回值

成功返回0,失败返回-1
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.

3.listen

#include <sys/types.h>        
#include <sys/socket.h>
int listen(int sockfd, int backlog);

//实例
iRet = listen(iSocketServer,BACKLOG);

3.1 sockfd

socket函数返回标识socket的整数。
sockfd = socket(AF_INET,SOCK_STREAM, 0);

3.2 backlog

最大连接数。

The backlog argument defines the maximum length to which the queue of pending connections for sockfd may grow.

3.3 返回值

成功返回0,失败返回-1
On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

4.accept

服务端,在bind后,并且listen后,可以用这个**等待客户端连接,并保存客户端的地址信息到addr

The argument sockfd is a socket that has been created with socket(2), bound to a local address with bind(2), and is listening for connections after a listen(2).

#include <sys/types.h>          
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

//实例
iAddrLen = sizeof(struct sockaddr);
iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);

4.1 sockfd

服务端的socket函数返回标识socket的整数。

sockfd = socket(AF_INET,SOCK_STREAM, 0);

4.2 addr

用于缓存客户端的地址变量地址。

struct sockaddr_in tSocketClientAddr;
iAddrLen = sizeof(struct sockaddr);
iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);

4.3 addrlen

前面地址的大小。
sizeof(struct sockaddr)

4.4 返回值

成功就返回连接的客户端的socket,失败返回-1
On success, these system calls return a nonnegative integer that is a file descriptor for the accepted socket. On error, -1 is returned, and errno is set appropriately.

5.recv

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

//实例
iRecvLen = recv(iSocketClient, buff, 999, 0);

5.1 sockfd

客户端标识符

5.2 buf

字符串缓存数组地址

5.3 len

读取信息长度

5.4 flags

0:常规操作,与read()相同
MSG_DONTWAIT:将单个I/O操作设置为非阻塞模式
MSG_OOB:指明发送的是带外信息
MSG_PEEK:可以查看可读的信息,在接收数据后不会将这些数据丢失
MSG_WAITALL:通知内核直到读到请求的数据字节数时,才返回。

5.5 返回值

返回接收到数据的长度,错误返回-1
These calls return the number of bytes received, or -1 if an error occurred.

6.send

向已连接的socket写入数据。
The send() call may be used only when the socket is in a connected state (so that the intended recipient is known). The only difference between send() and write(2) is the pres‐
ence of flags. With a zero flags argument, send() is equivalent to write(2)

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

//实例
iSendLen = send(iSocketClient,buff,strlen(buff),0);

6.1 sockfd

要写入socket的标识符

6.2 buf

要写入数据

6.3 len

写入数据长度

6.4 flags

flags取值有:
0: 与write()无异
MSG_DONTROUTE:告诉内核,目标主机在本地网络,不用查路由表
MSG_DONTWAIT:将单个I/O操作设置为非阻塞模式
MSG_OOB:指明发送的是带外信息

6.5 返回值

On success, these calls return the number of bytes sent. On error, -1 is returned, and errno is set appropriately.

7.sendto

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);

//实例
iAddrLen = sizeof(struct sockaddr);
iSendLen = sendto(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0,
			                      (const struct sockaddr *)&tSocketServerAddr, iAddrLen);

8.recvfrom

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);

//实例
iAddrLen = sizeof(struct sockaddr);
		iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
		if (iRecvLen > 0)
		{
			ucRecvBuf[iRecvLen] = '\0';
			printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);
		}

9.close

 #include <unistd.h>
 int close(int fd);
 close(iSocketClient);

10 常用函数

//整型转网络端口号
#include <arpa/inet.h>
htons(SERVER_PORT);
//字符地址转换成网络地址
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
inet_aton(argv[1], &tSocketServerAddr.sin_addr)
//网络地址转换成字符地址
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
inet_ntoa(tSocketClientAddr.sin_addr)

(二):TCP

TCP server

Created with Raphaël 2.3.0 socket bind listen accept recv/send close
/*server.c*/

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

#define SEVEER_PORT 8888  //port
#define BACKLOG     10    //max connection

int main(int argc, char **argv)
{
    int iSocketServer;
    int iSocketClient;
    int iRet;
    int iAddrLen;
    int iClientNum=-1;
    int iRecvLen;
    unsigned char buff[1000];
	//解决僵尸进程问题
    signal(SIGCHLD,SIG_IGN);
 
    //set address
    struct sockaddr_in tSocketServerAddr;
    struct sockaddr_in tSocketClientAddr;
    tSocketServerAddr.sin_family = AF_INET;
    tSocketServerAddr.sin_port   = htons(SEVEER_PORT); //htons host to net short
    tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;    //接收任何IP
    memset(tSocketServerAddr.sin_zero, 0, 8);          //置零
    //scoket
    iSocketServer = socket(AF_INET,SOCK_STREAM, 0);
    if (iSocketServer==-1){
        printf("socket error!\n");
        return -1;
    }
    //bind
    iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr,sizeof(struct sockaddr));
    if (iRet==-1){
        printf("bind error!\n");
        return -1;
    }
    //listen
    iRet = listen(iSocketServer,BACKLOG);
    if(iRet==-1){
        printf("listen error!\n");
    }
    //accept
    while(1){
        iAddrLen = sizeof(struct sockaddr);
        iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
        if(iSocketClient!=-1){
            iClientNum++;
            printf("connect from client %d :%s\n",iClientNum,inet_ntoa(tSocketClientAddr.sin_addr));
            //fork
            if(!fork()){
                while(1){
                    //recv
                    iRecvLen = recv(iSocketClient, buff, 999, 0);
                    if(iRecvLen<=0){
                        //close
                        close(iSocketClient);
                        return -1;
                    }else{
                        buff[iRecvLen]='\0';
                        printf("client %d recv:%s\n",iClientNum,buff);
                    }
                }
            }
        }
    }
    //close
    close(iSocketServer);
    return 0;
}

TCP client

Created with Raphaël 2.3.0 socket connect send/recv close
/*client.c*/
#include <sys/types.h>          
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

#define SEVEER_PORT 8888  //port

int main(int argc, char **argv)
{
    int iSocketClient;
    int iRet;
    int iSendLen;
    unsigned char buff[1000];
    if(argc!=2){
        printf("Usage:\n");
        printf("%s <server ip>\n",argv[0]);
        return -1;
    }
    //set address
    struct sockaddr_in tSocketServerAddr;
    tSocketServerAddr.sin_family = AF_INET;
    tSocketServerAddr.sin_port   = htons(SEVEER_PORT); //htons host to net short
    //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;    //接收任何IP
    if(inet_aton(argv[1],&tSocketServerAddr.sin_addr)==0){
        printf("invalid server ip\n");
        return -1;
    }
    memset(tSocketServerAddr.sin_zero, 0, 8);          //置零
    //scoket
    iSocketClient = socket(AF_INET,SOCK_STREAM, 0);
    if (iSocketClient==-1){
        printf("socket error!\n");
        return -1;
    }
    //connect
    iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr,sizeof(struct sockaddr));
    if (iRet==-1){
        printf("connect error!\n");
        return -1;
    }
    //send
    while(1){
        if(fgets(buff,999,stdin)){
            iSendLen = send(iSocketClient,buff,strlen(buff),0);
            if(iSendLen<=0){
                close(iSocketClient);
                return -1;
            }
        }
    }
    return 0;
}

(三):UDP

server

Created with Raphaël 2.3.0 socket bind listen recvfrom/sendto close
/*server.c*/

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

/* socket
 * bind
 * sendto/recvfrom
 */

#define SERVER_PORT 8888
int main(int argc, char **argv)
{
	int iSocketServer;
	int iSocketClient;
	struct sockaddr_in tSocketServerAddr;
	struct sockaddr_in tSocketClientAddr;
	int iRet;
	int iAddrLen;
	int iRecvLen;
	unsigned char ucRecvBuf[1000];
	int iClientNum = -1;
	
	iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);
	if (-1 == iSocketServer)
	{
		printf("socket error!\n");
		return -1;
	}

	tSocketServerAddr.sin_family      = AF_INET;
	tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
 	tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
	memset(tSocketServerAddr.sin_zero, 0, 8);
	
	iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
	if (-1 == iRet)
	{
		printf("bind error!\n");
		return -1;
	}
	while (1)
	{
		iAddrLen = sizeof(struct sockaddr);
		iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
		if (iRecvLen > 0)
		{
			ucRecvBuf[iRecvLen] = '\0';
			printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);
		}
	}	
	close(iSocketServer);
	return 0;
}

client

Created with Raphaël 2.3.0 socket connect recvfrom/sendto/send/recv close
/*client.c*/
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
/* socket
 * connect
 * send/recv
 */

#define SERVER_PORT 8888

int main(int argc, char **argv)
{
	int iSocketClient;
	struct sockaddr_in tSocketServerAddr;
	
	int iRet;
	unsigned char ucSendBuf[1000];
	int iSendLen;
	int iAddrLen;

	if (argc != 2)
	{
		printf("Usage:\n");
		printf("%s <server_ip>\n", argv[0]);
		return -1;
	}

	iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);

	tSocketServerAddr.sin_family      = AF_INET;
	tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
 	//tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
 	if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
 	{
		printf("invalid server_ip\n");
		return -1;
	}
	memset(tSocketServerAddr.sin_zero, 0, 8);

#if 0
	iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));	
	if (-1 == iRet)
	{
		printf("connect error!\n");
		return -1;
	}
#endif

	while (1)
	{
		if (fgets(ucSendBuf, 999, stdin))
		{
#if 0
			iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
#else
			iAddrLen = sizeof(struct sockaddr);
			iSendLen = sendto(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0,
			                      (const struct sockaddr *)&tSocketServerAddr, iAddrLen);

#endif
			if (iSendLen <= 0)
			{
				close(iSocketClient);
				return -1;
			}
		}
	}	
	return 0;
}

结语

上面的TCP,UDP实现是参考韦东山老师的视频里的代码的,https://www.bilibili.com/video/BV1w4411B7a4?p=66&vd_source=9385b7f8c739b9e3ef3f21ddaebd2eb9

TCP运行截图
请添加图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值