(1)发送端:将信息以规定的协议组装成数据包。
(2)接收端:对收到的数据包解析,以提取所需要的信息。
Socket:两个在网络上的程序通过一个双向的通信连接,实现数据的交换,此连接的一端称为一个socket。
Socket对本质:Socket是一个编程接口, tcp/ip协议提供做网络开发对接口,
网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。中间最主要的就是数据包的组装,数据包的过滤,数据包的捕获,数据包的分析,当然最后再做一些处理,代码、开发工具、数据库、服务器架设和网页设计这5部分你都要接触。
IPv4地址结构示例
struct sockaadr_in mysock;
mysock.sin_family = AF_INET; // ???TCP地址结构
mysock.sin_port = htons(3333); // ??? 字节顺序转换函数
mysock.sin_addr.s_addr = inet_addr("166.111.160.10"); //设置IP地址
//如果mysock.sin_addr.s_addr = INADDR_ANY,则不指定IP地址(用于server程序)
bzero(&(mysock.sin_zero),8); //设置sin_zero为8位保留字节
IP地址转换函数
inet_aton():将字符串形式的IP地址转换成二进制形式的IP地址,成功返回1,否则返回0,转换后的IP地址存储在参数inp中。
inet_ntoa():将32位二进制形式的IP地址转换为数字点形式的IP地址,结果在函数返回值中返回。
网络字节序
字节序,顾名思义字节的顺序,就是大于一个字节的数据在内存中的存放顺序。
在跨平台以及网络程序应用中字节序才是一个应该被考虑的问题。
网络字节序是TCP/IP规定的一种数据表示格式,与具体的CPU类型、操作系统无关,从而可以保证数据在不同主机之间传输时能被正确解释。网络字节顺序采用big endian(大端字节序)。
Intel x86系列CPU使用的都是little endian(小端字节序)
大端字节序(big-endian):低地址存放最高有效字节
小端字节序(little-endian):低地址存放最低有效字节
例如数字0x12345678(DWORD)在两种不同字节序CPU中的存储顺序如下所示:
下面四个函数分别用于长整型和短整型数在网络字节序和主机字节序之间进行转换,其中s指short,l指long,h指host,n指network
套接字标识TCP/IP的连接
使用套接字要注意:
1、sockaddr与sockaddr_in的区别
2、网络字节顺序
了解套接字的工作原理
掌握套接字的通信过程
https://blog.youkuaiyun.com/h674174380/article/details/76738086
/*****服务器 ****/
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
int main()
{
int iListenFd, connfd,n,i;
struct sockaddr_in servAddr, cliAddr; // 服务器客户端和网络地址
socklen_t cliLen; // 地址长度(服务器)
pid_t childPid; // 进程标识符
char msg[1000];
iListenFd = socket(AF_INET, SOCK_STREAM, 0); // creat socket
bzero(&servAddr, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(32000);
servAddr.sin_add.s_addr = htonl(INADDR_ANY); // 表示本地任意对宏
bind(listenfd, (struct sockaddr *)&servAddr , sizeof(servAddr));
// 绑定IP地址,端口号,到要监听到套接口上
listen(iListenFd, 1024); // 等到套接口到链接
for(;;)
{
cliLen = sizeof(cliAddr); // 取客户端地址到长度
connfd = accept(iListenFd, (struct sockaddr *)&cliAddr, &cliLen);
// 父进程 : 用于创建链接,哪个客户端和哪个服务器链接
// 输入监听套接口 返回新一个的链接套接口
// 处于阻塞状态
if (((childPid == fork()) == 0 )
// 子进程:以并发的方式处理客户端的信息
// 如果没有上下两句,那么服务器处理的方式为循环方式
{
close(listenfd); // 关闭监听套接字
for(;;) // 表示服务器可以一直通信
{
n = recvfrom(connfd, msg, 1000, 0, (struct sockaddr *)&cliAddr, &cliLen);
// 接收客户端信息
if (n == 0)
{
printf("the client %s is closed\n",inet_ntoa(cliaddr.sin_addr.s_addr));
break;
}
printf("---------------------\n");
printf("---------------------\n");
msg[n] = '\0';
printf("%s\n",msg);
// 将客户端发送端消息显示在服务器上
for(int i = 0; i < n; i++)
{
msg[i] = toupper(msg[i]);
}
// 将收到的小写字母转为大写字母
sendto(connfd, msg, n, 0, (struct sockaddr*)&cliAddr, sizeof(cliAddr));
// 服务器发送给客户端变化信息
}
close(connfd);
}
}
close (listenfd);
return 0;
}
1: 阻塞型???
2:close int??
3: