分类: LINUX
2010-07-16 21:51:38
Socket是bsd提供的网络应用编程的接口,现在它已经是网络编程的标准;是一种特殊的进程间通信方式,不同机器上的进程都可以使用这种方式进行通信。
l 网络中的数据传输是一种I/O操作
l Socket也是一种文件描述符,它代表了一个通信管道的一个端点
l read,write,close操作可应用于Socket描述符
l 在socket类型的文件描述符上,可以完成建立连接,数据传输等操作
l 常用的Socket类型有两种
ü 流式Socket-SOCK_STREAM,提供面向连接的Socket
ü 数据报式Socket-SOCK_DGRAM,提供面向无连接的Socket
l 字节序是一个处理器的架构特性
ü 大端格式
ü 小端格式
Ø 以上返回网络字节序
uint32_t htonl(uint32_t hostint32);
uint16_t htons(uint16_t hostint16);
Ø 以上返回主机字节序
uint32_t ntohl(uint32_t netint32);
uint16_t ntohs(uint16_t netint16);
地址标识了特定通信域中的套接字端点,地址格式与特定通信域相关,为了使不同格式地址能被传入套接字函数,地址被强制转换成通用的地址结构sockaddr表示.
struct sockaddr{
sa_family_t sa_family;//协议
char sa_data[14];//ip地址
};
因特网地址定义在<netinet/in.h>中.在IPV4因特网域(AF_INET)中,套接字地址用如下结构sockaddr_in表示.
struct in_addr{
in_addr_t s_addr;
};
struct sockaddr_in{
sa_family_t sin_family;
in_port_t sin_port;//2
struct in_addr sin_addr;//4
unsigned char sin_zero[8];//8
};
4.1.5、网络地址与ip字符串转换
《1》inet_addr():
将一个点间隔地址转换成一个in_addr,返回一网络字节顺序表示的Internet地址。使用:server_addr.sin_addr.s_addr = inet_addr("192.168.0.10");
《2》inet_aton()
将字符串表示的网络地址转换为该地址数值的整数表示,返回的数字总是按照网络字节顺序的。
inet_addr与inet_aton的区别:
inet_aton认为255.255.255.255是无效的,不能对这个地址操作。而inet_addr可以。
《3》inet_ntoa()
给定一个数字网络地址,返回作为字符串的该地址的电地址表示。
《4》htons或htonl
将以主机字节顺序的数转换为一网络字节书序表示的数。htons转16位的(host to network short), htonl转32位的(host to network long);
通常用法:
server_addr.sin_port = htons(2222); //端口号
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY=0 所以等效于:server_addr.sin_addr.s_addr = INADDR_ANY;
INADDR_ANY: 表示任意的IP地址,一般为内核指定的,大多数系统取0。
htonl()简单说是一个把本机IP转化为网络协议中规定的格式的函数.也 就是所谓的大端模式或小端模式。
《5》常用函数inet_addr()、inet_aton()、inet_ntoa() 和 htons()。
《6》struct in_addr以一个32位无符号数来表示,通常需要用到点分十进制数串 与它之间的转换:int inet_pton(int family, const char *strptr, void *addrptr);
成功返回1,否则返回0
《7》const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
len代表strptr缓冲区的长度
#define INET_ADDRSTRLEN 16
#include
Tcp模型:
Udp模型:
创建套接字是进行任何网络通信时必须做的第一步,创建一个用于网络通信的I/O描述符(套接字)
v 格式:int socket(int family, int type,int protocol);
v 参数:
u family:协议族
AF_INET,AF_INET6,AF_LOCAL,AF_ROUTE,AF_KEY
u type:套接口类型
SOCK_STREAM,SOCK_DGRAM,SOCK_SEQPACKET, SOCK_RAW
u protocol:协议类别
0,IPPROTO_TCP,IPPROTO_UDP,IPPROTO_SCTP
v 返回值:套接字
做为服务器需要具备的条件:
ü 具备一个可以确知的地址,以便让别人找到我
ü 使用socket创建一个套接字时,系统不会分配一个理想的端口
ü 让操作系统知道你是一个服务器,而不是一个客户端
ü 使用socket创建的是主动套接字,但是作为服务器,需要被动等待别人连接
ü 等待连接的到来
ü 对于面向连接的TCP协议来说,连接的建立才真正意味着数据通信的开始
ü 使用一个确知的端口来接收客户端的连接
bind函数将一个地址绑定到套接字
v 格式:int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);
v 参数:
sockfd:socket套接口描述字
myaddr:指向特定于协议的地址结构指针
addrlen:该地址结构的长度
v 返回值:0,成功;其他,失败
v 例子:
#include
unsigned short port = 8000;
struct sockaddr_in serverAddr;
bzero(&serverAddr, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);//inet_addr("192.168.220.13")
bind(listenfd, (struct sockaddr*)&serverAddr,sizeof(struct sockaddr));
Listen函数可以将套接口由主动修改为被动,操作系统为该套接口设置一个连接队列,来记录所有连接到该套接口的连接
v 格式:int listen(int sockfd, int backlog);
v 参数:
sockfd:socket套接口描述字
backlog:连接队列的长度 //默认为5
v 返回值:0,成功;其他,失败
等待连接的到来,Accept函数从连接队列中取出一个已经建立的连接,同时建立通信套接字;如果没有任何连接可用,则进入睡眠等待
v 格式:int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
v 参数:
sockfd:socket套接口描述字
cliaddr: 客户端地址
addrlen:客户端地址结构体长度
v 返回值:已连接的套接口
注:accept函数返回的是一个套接口,这个套接口代表了当前这个连接
v 例子:
char ip[INET_ADDRSTRLEN];
unsigned short port;
int connfd;
struct sockaddr_in cliAddr;
int addrlen;
bzero(& cliAddr, sizeof(cliAddr));
connfd = accept(listenfd, (struct sockaddr*)&cliAddr, &addrlen);
printf(“client ip=%s\n”, inet_ntop(AF_INET, &cliAddr.sin_addr.s_addr, ip, INET_ADDRSTRLEN));
read(connfd, buf, 1024);
作为客户端需要具备的条件:知道服务器的IP地址以及端口号
连接建立才可以开始传输数据(对于TCP协议)
v 格式:int connect(int sockfd,const struct sockaddr *addr,socklen_t len);
v 参数:
sockfd:socket套接口描述字
addr: 服务器地址
addrlen:服务器地址结构体长度
v 返回值:0,成功;其他,错误
connect函数建立连接之后不会产生新的套接口
#include
char *ip = “192.168.0.1”;
unsigned short port = 8000;
struct sockaddr_in serverAddr;
bzero(&serverAddr, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
//serverAddr.sin_addr.s_addr=inet_addr("192.1680.1");或
inet_pton(AF_INET, ip, &serverAddr.sin_addr.s_addr);
connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr));
当连接建立后,通信的两端便具备了两个套接口
套接口也是一种文件描述符,所以read、write函数可以用于从这个通信管道取出或向其写入数据
int fd;
char buf[100];
fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr));
……
write(fd, buf, 100);
read(fd, buf, 100);
close(fd);
v 发送函数
ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);//tcp
ssize_t sendto(int sockfd, const void *buf, size_t nbytes, int flags,
const struct sockaddr *destaddr, socklen_t destlen);//ip
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
v 接收函数
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);//tcp
ssize_t recvfrom(int sockfd, void*restrict buf, size_t len, int flags,
struct sockaddr *restrict addr, socklen_t *restrict addrlen);//udp
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
关闭一个代表已建立连接的套接字将导致另一端接收到一个0长度的数据包
ü 做服务器时
关闭socket创建的套接字将导致服务器无法继续接受新的连接,但不会影响 已经建立的连接;
关闭accept返回的套接字将导致它所代表的连接被关闭,但不会影响服务器 的监听
ü 做客户端时