文章目录
网络编程
1. 网络通信结构
1.1 Socket网络通信与IPC机制
- IPC
消息队列、共享内存、IPC信号量
结构麻烦、不易使用、仅用于同机进程间通信
- Socket网络通信
标准、规范,基于TCP/IP协议
两种模式:TCP通信(与管道类似)、UDP通信(与消息队列类似)
易于理解、使用,使用广泛
既可用于单机进程间通信,也可用于不同计算机进程间通信
1.2 客户服务器模型
- 与网络通信一般采取客户服务器模型
1.3 网络通信结构
- 分层设计
- 各层分工明确
- 可靠性好,性能高
1.4 套接字编程模型
结构:网卡、TCP协议、套接字(Socket)
类比:网卡(单位门牌号)、TCP/IP协议(收发室)、套接字(信箱号)
套接字:含有进程接收信息的完整地址(Socket地址:IP地址、端口号)
1.5 因特网连接(TCP连接)
TCP连接:比喻连接通信双方套接字的一条通信线路,通信前建立,通信结束拆除
一条TCP连接实际上就是一个文件描述
可用read/write或send/recv进行数据收发
地址:(cliaddr:cliport, servaddr:servport)
1.6 因特网连接实例
服务器端口号:规定为80
客户端端口号:随机分配,12345
2. 套接字地址设置
2.1 地址结构
/* Intenet-style socket address structure */
struct sockaddr_in
{
short sin_family; //指定地址家族即地址格式
unsigned short sin_port; //端口号码
struct in_addr sin_addr; //IP地址
char sin_zero[8]; //需要指定为0
};
在这个结构中,成员sin_family指定使用该套接字地址的地址家族。在这里必须设置为AF_INET,表示程序所使用的地址家族是TCP/IP。
注意:该结构的最后一个成员并未实际使用,主要是为了与第一个版本的套接字地址结构大小相同而设置。在实际使用时,将这8个字节直接设为0即可。
struct sin_addr {
unsigned int s_addr; /*network byte order (big-endian) */
};
2.1.1 字节序
整数:unsigned int B[2]={0x12345678,0xabcdef},
void A=(void) B;
unsigned int *K=(int *)malloc(sizeof(int));
*K=0x12345678;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BK8EzXP9-1590747953341)(F:\markdown\网络编程\1590714503(1)].jpg)
2.1.2 主机序、网络序转换
/*host to network long*/
unsigned long int htonl(unsigned long int hostlong);
/*主机字节序转化为网络字节序*/
unsigned short int htons(unsigned short int hostshort);
返回:按照网络字节顺序的值。
unsigned long int ntohl(unsigned long int netlong);
unsigned short int ntohs(unsiged short int netshort);
h:host
n:network
l:long, int,4字节
s: short, 2字节
#include "wrapper.h"
int main(){
unsigned int m,n; unsigned short k; char *a,*b,*c;
m=0x12345678; n=htonl(0x12345678);
a=(char*)&m; b=(char*)&n; c=(char*)&k;
c[0]='1';c[1]='2';
printf("a[]=%2x%2x%2x%2x\n",a[0],a[1],a[2],a[3]);
printf("b[]=%2x%2x%2x%2x\n",*b,*(b+1),*(b+2),*(b+3));
printf("k=%x\n",k);
}
/*主机采用小端模式分析*/
2.2 IP地址
- 32位整数(大端模式,网络序):
struct in_addr IP1=htonl(0x8002c2f2);
80 02 c2 f2
128=0x80,2=0x02,193=0xc2,242=0xf2
- 点分十进制:
128.2.193.242
- 转换函数:
int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);
/*a: 字符串 n:32位整数*/
2.3 因特网域名
/* DNS host ent ry structure ,位于系统头文件netdb.h */
struct hostent {
char *h_name; /* Official domain name of host */
char **h_aliases; /* Null-terminated array of domain name */
int h_addrtype; /* Host address type(AF_INET */
int h_length; /* Length of an address, in bytes */
char **h_addr_list; /* Null-terminated array of in_addr structs */
};
- 查询域名和IP地址
- 命令
nslookup www.baidu.com
- API函数
struct hostent *gethostbyname(const char *name);
struct hostent *gethostbyaddr(const char *addr, int len, int type);
- c文件(hostinfo.c)
#include "wrapper.h"
int main(int argc, char **argv)
{
char **pp;
struct in_addr addr;
struct hostent *hostp;
if (argc != 2) { … }
if (inet_aton(argv[1], &addr) != 0)
hostp = Gethostbyaddr((const char *)&addr, sizeof(addr), AF_INET);
else
hostp = Gethostbyname(argv[1]);
printf("official hostname: %s\n", hostp->h_name);
for (pp = hostp->h_aliases; *pp != NULL; pp++)
printf("alias: %s\n", *pp);
for (pp = hostp->h_addr_list; *pp != NULL; pp++) {
addr.s_addr = *((unsigned int *)*pp);
printf("address: %s\n", inet_ntoa(addr));
}
exit(0);
}
$ ./hostinfo 219.222.191.131
official hostname: sw.dgut.edu.cn
address: 219.222.191.131
$ ./hostinfo www.dgut.edu.cn
official hostname: www.dgut.edu.cn
address: 219.222.191.1
address: 113.105.128.128
3.网络通信API函数
3.1 编程框架
3.2 网络通信API函数
3.2.1 客户端
- 创建套接字
int socket(int af, int type , int protocol);
int af;
//指定套接字所使用的地址格式,设置为AF_INET
int type;
//套接字类型, SOCK_STREAM 表示采用TCP 协议通信,采用UDP 协议通信,则为SOCK_DGRAM
int protocol ;
//如果参数type已经指定套接字类型为TCP或UDP,则该参数可以设置为0,e.g:
client_sock = socket(AF_INET , SOCK_STREAM, 0);
- connect函数
int connect (
int client_sock,
//套接字句柄
struct sockaddr *serv_addr,
//将要连接的服务器地址信息结构指针
int addrlen
//地址信息结构体长度
);
- 包装函数open_client_sock
int open_client_sock(char *hostname, int port)
{
int client_sock; struct hostent *hp;
struct sockaddr_in serveraddr;
if ((client_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1; /* if error return -1 */
/* Fill in the server's IP address and port */
if ((hp = gethostbyname(hostname)) == NULL)
return -2; /* if error return -2 */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *) hp->h_addr_list[0],
(char *)&serveraddr.sin_addr.s_addr, hp->h_length);
serveraddr.sin_port = htons(port);
/* Establish a connection with the server */
if (connect(client_sock, (SA *) &serveraddr, sizeof(serveraddr)) < 0)
return -1;
return client_sock;
}
3.2.2 服务器端
int bind(int serv_sock, struct sockaddr *my_addr , int addrlen);
int listen(int serv_sock, int backlog);
- open_listen_sock包装函数:
int open_listen_sock(int port)
{ int listen_sock, optval=1;
struct sockaddr_in serveraddr;
/* Create a socket descriptor */
if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
/* Eliminates "Address already in use" error from bind */
if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int)) < 0)
return -1;
/* listen_sock is an endpoint for all requests to port received
from any IP address for this host */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if (bind(listen_sock, (SA *)&serveraddr, sizeof(serveraddr)) < 0)
return -1;
/* convert the the sock to a listening socket ready to accept connection requests */
if (listen(listen_sock, LISTENQ) < 0)
return -1;
return listen_sock;
}
3.2.3 数据收发
ssize_t send(int sock, const void *buff, size_t nbytes, int flags);
/*返回: 若成功则为实际发送字节数,若出错则为SOCKET_ERROR.*/
ssize_t recv(int sock, void *buff, size_t nbytes, int flags);
/*返回: 若成功返回实际接收字节数,若出错则为SOCKET_ERROR,如果recv函数在等待协议接收数据时网络中断了,则返回0*/
4. 本文目的
学习操作系统-网络编程板块知识,分享学习过程
5. 资料来源
- 网络
- 书籍
- 课件