接上一篇: IPV4流媒体广播系统03
1. 网络套接字
2.
1.取得SOCKET
2.给SOCKET取得地址(可省略)
3.收/发消息
4.关闭SOCKET
开发思路:
(1) man socket
socket()函数的作用:socket() creates an endpoint for communication and return
s a descrip-tor.
int socket(int domain, int type, int protocol);
第一个参数是协议族,这里选AF_INET 表示ipv4
第二个参数是 传输数据的类型,这里选 SOCK_DGRAM 传输报文
第三个参数 直接写0 不用管他
返回值: 返回一个文件描述符,man socket 中的原话是这样
RETURN VALUE
On success, a file descriptor for the new socket is returned. On
error, -1 is returned, and errno is set appropriately.
(2) man 2 bind
NAME
bind - bind a name to a socke
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
第二个参数的描述是:
第二个参数实际上不存在,是捏造的,他取决于你用的 address family协议 , 你用哪个协议族,就把你的协议族的地址填在那儿
The actual structure passed for the addr argument will depend on the
address family. The sockaddr structure is defined as something like:
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
The only purpose of this structure is to cast the structure pointer
passed in addr in order to avoid compiler warnings. See EXAMPLE
below.
你用的是哪个协议就去哪个协议找对应的 address families
The rules used in name binding vary between address families. Consult
the manual entries in Section 7 for detailed information. For AF_INET
see ip(7), for AF_INET6 see ipv6(7), for AF_UNIX see unix(7), for
AF_APPLETALK see ddp(7), for AF_PACKET see packet(7), for AF_X25 see
x25(7) and for AF_NETLINK see netlink(7).
我们这里用的协议是 AF_PACKE 我们去看一下 第7章 使用命令 man 7 ip
Address format
An IP socket address is defined as a combination of an IP interface
address and a 16-bit port number. The basic IP protocol does not sup‐
ply port numbers, they are implemented by higher level protocols like
udp(7) and tcp(7). On raw sockets sin_port is set to the IP protocol.
//我们用用到的就是 ipv4 ,使用 sockaddr_in 这个结构体
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
第5个参数对端地址是,回填的数据
传输的报文
proto.h
#ifndef PROTO_H__
#define PROTO_H__
#define PROTO_H__
#define RCVPORT "1989"
#define NAMESIZE 11
struct msg_st
{
uint8_t name[NAMESIZE];
uint32_t math;
uint32_t chinese;
}__attribute__((packed));
#endif
服务端接收报文:
#include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h> /* See NOTES */
4 #include <sys/socket.h>
5 #include <arpa/inet.h>
6 #include "proto.h"
7 #define IPSTRSIZE 40
8 int main()
9 {
10 int sd;
11 struct sockaddr_in laddr,raddr;
12 char ipstr[IPSTRSIZE];
13 sd = socket(AF_INET,SOCK_DGRAM,0);//第一个参数是ipv4,第二个是数据格
式是//报文
14 struct msg_st rbuf;//我知道你要给我发结构体来,我要定义一个接收
15 socklen_t raddr_len;
16 if(sd<0)
17 {
18 perror("socket()");
19 exit(1);
20 }
laddr.sin_family = AF_INET;
22 laddr.sin_port = htons(atoi(RCVPORT));
23
24 //inet_pton可以把ip地址点分式转换成大整数
25 //@parm1: 协议族ipv4或ipv6 @parm2:source 也就你自己的ip,0.0.0.0 万能地址,本
机
26 //@parm3: 转换完放到的位置
27 inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);
28 if(bind(sd,(void *)&laddr,sizeof(laddr))<0)
29 {
30 perror("bind()");
31 exit(1);
32 }
33 raddr_len = sizeof(raddr);//必须初始化
34 while(1)
35 {
36 recvfrom(sd,&rbuf,sizeof(rbuf),0,(void *)&raddr,&raddr_len);
37 //第5个参数 是回填的.
// inet_notp 把一个大整数转化成点分式
39 inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE);//@parms1 协议族 @parms
2 带//转换的参数
40 //@parms3 放到那块空间去 @parm4 那块空间有多大
41 printf("----Message from %s:%d--\n",ipstr,ntohs(raddr.sin_port));
42 printf("NAME = %s\n",rbuf.name);
43 printf("MATH = %d\n",ntohl(rbuf.math));
44 printf("CHINESE = %d\n",ntohl(rbuf.chinese));
45
46 }
47 close(sd);
48 exit(0);
49
50 }
netstat -anu
客户端代码:
#include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h> /* See NOTES */
4 #include <sys/socket.h>
5 #include <arpa/inet.h>
6 #include <string.h>
7 #include "proto.h"
8 #define IPSTRSIZE 40
9
10 int main(int argc,char * argv[])
11 {
12 if(argc<2)
13 {
14 fprintf(stderr,"Usage...\n");
15 exit(1);
16 }
17 int sd;
18 struct sockaddr_in raddr;
19 char ipstr[IPSTRSIZE];
20 sd = socket(AF_INET,SOCK_DGRAM,0);//第一个参数是ipv4,第二个是数据格
//式是报文
struct msg_st sbuf;//我知道你要给我发结构体来,我要定义一个接收
22 socklen_t raddr_len;
23 if(sd<0)
24 {
25 perror("socket()");
26 exit(1);
27 }
28
29 //构造数据
30 strcpy(sbuf.name,"xiaoming");
31 sbuf.math = htonl(rand()%100);
32 sbuf.chinese = htonl(rand()%100);
33 raddr.sin_family = AF_INET;
34 raddr.sin_port = htons(atoi(RCVPORT));
35 inet_pton(AF_INET,argv[1],&raddr.sin_addr);
if(sendto(sd,&sbuf,sizeof(sbuf),0,(void *)&raddr,sizeof(raddr))<0)
39 {
40 perror("sendto()");
41 exit(1);
42 }
43 puts("OK!");
44 close(sd);
45 exit(0);
46
47 }
整体效果: