1.socket
一般来说socket有一个别名也叫做套接字。
socket起源于Unix,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
说白了Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议,而不需要让用户自己去定义什么时候需要指定哪个协议哪个函数。
其实socket也没有层的概念,它只是一个facade设计模式的应用,让编程变的更简单。是一个软件抽象层。在网络编程中,我们大量用的都是通过socket实现的。
按照一切皆文件的设计原则 套接字描述符其实也就是一个整数,就是文件描述符
2.针对套接字的系统数据结构:
1)、套接字API里有个函数socket,它就是用来创建一个套接字。套接字设计的总体思路是,单个系统调用就可以创建任何套接字,因为套接字是相当笼统的。一旦套接字创建后,应用程序还需要调用其他函数来指定具体细节。例如调用socket将创建一个新的描述符条目:
2)、虽然套接字的内部数据结构包含很多字段,但是系统创建套接字后,大多数字字段没有填写。应用程序创建套接字后在该套接字可以使用之前,必须调用其他的过程来填充这些字段。
详细介绍
3.一个demo
协议头文件
#define NAMESIZE 11
#include <stdint.h>
//指定接收的端口号
#define RCVPORT 1989
//要发送的结构体
struct msg_st
{
//不能用char int 因为环境不同
uint8_t name[NAMESIZE];
uint32_t math;
uint32_t eng;
}__attribute((packed));//防止内存对齐
//因为是跨主机 你不知道对方主机的对齐格式
#endif
rcver.c
#define SIZE 40
int main()
{
int sd;//socket 套接字
struct sockaddr_in laddr , raddr;
struct msg_st buf;
socklen_t raddr_len;
char ipstr[SIZE];
//创建一个socket套接字
//IPV4协议族 中的UDP协议 来传输数据报
sd = socket(AF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/);
if(sd < 0)
{
perror("socket()");
exit(1);
}
laddr.sin_family = AF_INET;//协议族
laddr.sin_port = htons(RCVPORT);//端口号
inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr);
//ip地址转化成大整数
//将socket套接字 和 ip端口号进行绑定
if(bind(sd, (void*)&laddr, sizeof(laddr)) < 0)
{
perror("bind()");
exit(1);
}
/*!!!!!*/
raddr_len = sizeof(raddr);
while(1)
{
//开始接受数据
//从socket套接字 放到buf中 指定buf大小
//由于是无连接 所以发送端口的信息回填到raddr中
recvfrom(sd, &buf, sizeof(buf), 0,
(void *)&raddr, &raddr_len);
//把addr里面的ip大整数变成字符串
inet_ntop(AF_INET, &raddr.sin_addr, ipstr, SIZE);
//进行输出 注意网络字节序的问题
printf("MSG FROM **** %s:%d*****\n",
ipstr, ntohs(raddr.sin_port));
printf("NMAE = %s\n", buf.name);
printf("MATH = %d Eng = %d\n",
ntohl(buf.math), ntohl(buf.eng));
}
close(sd);
return 0;
}
snder.c
发送方不用绑定一个端口 bind
int main(int argc, char *argv[])
{
int sd;
struct sockaddr_in raddr;
struct msg_st buf;
if(argc < 2)
{
fprintf(stderr, "No Enough\n");
exit(1);
}
//也是获取一个socket套接字
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("socket()");
exit(1);
}
//初始化要发送的对象 注意字节序
strcpy(buf.name, "ZHUZHENGHUA");
buf.math = htonl(rand()%100);
buf.eng = htonl(rand()%100);
raddr.sin_family = AF_INET;//协议族
raddr.sin_port = htons(RCVPORT);//目标端口
inet_pton(AF_INET, argv[1], &raddr.sin_addr);//目的ip
//发送 套接字 要发送的东西 发送的地址
if(sendto(sd, &buf, sizeof(buf), 0, (void*)&raddr, sizeof(raddr)) < 0)
{
perror("sendto()");
exit(1);
}
puts("OK");
close(sd);
return 0;
}