Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1136913
  • 博文数量: 300
  • 博客积分: 37
  • 博客等级: 民兵
  • 技术积分: 772
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-26 04:46
文章分类
文章存档

2017年(4)

2016年(7)

2015年(19)

2014年(72)

2013年(71)

2012年(127)

分类:

2012-10-19 19:13:46

原文地址:Linux网络基础编程 作者:rojian

4.1.1、socket定义

Socket是bsd提供的网络应用编程的接口,现在它已经是网络编程的标准;是一种特殊的进程间通信方式,不同机器上的进程都可以使用这种方式进行通信。

l 网络中的数据传输是一种I/O操作

l Socket也是一种文件描述符,它代表了一个通信管道的一个端点

l read,write,close操作可应用于Socket描述符

l 在socket类型的文件描述符上,可以完成建立连接,数据传输等操作

l 常用的Socket类型有两种

ü 流式Socket-SOCK_STREAM,提供面向连接的Socket

ü 数据报式Socket-SOCK_DGRAM,提供面向无连接的Socket

4.1.2、字节序(字节的顺序)

l 字节序是一个处理器的架构特性

ü 大端格式

ü 小端格式

4.1.3、字节序转换函数#include

Ø 以上返回网络字节序

uint32_t htonl(uint32_t hostint32);

uint16_t htons(uint16_t hostint16);

Ø 以上返回主机字节序

uint32_t ntohl(uint32_t netint32);

uint16_t ntohs(uint16_t netint16);

4.1.4、地址结构

地址标识了特定通信域中的套接字端点,地址格式与特定通信域相关,为了使不同格式地址能被传入套接字函数,地址被强制转换成通用的地址结构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

4.2、tcp传输--面向连接

#include

4.2.1、创建套接字

创建套接字是进行任何网络通信时必须做的第一步,创建一个用于网络通信的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协议来说,连接的建立才真正意味着数据通信的开始

ü 使用一个确知的端口来接收客户端的连接

4.2.2、绑定套接字

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));

4.2.4、监听套接字:让套接字成为被动的

Listen函数可以将套接口由主动修改为被动,操作系统为该套接口设置一个连接队列,来记录所有连接到该套接口的连接

v 格式:int listen(int sockfd, int backlog);

v 参数:

sockfd:socket套接口描述字

backlog:连接队列的长度 //默认为5

v 返回值:0,成功;其他,失败

4.2.5、接收连接,并创建通信套接字

等待连接的到来,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地址以及端口号

4.2.6、客户端需要主动跟服务器建立连接

连接建立才可以开始传输数据(对于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);

4.2.7、套接字提供的发送接收函数

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);

4.2.8、使用close函数即可关闭套接字

关闭一个代表已建立连接的套接字将导致另一端接收到一个0长度的数据包

ü 做服务器时

关闭socket创建的套接字将导致服务器无法继续接受新的连接,但不会影响 已经建立的连接;

关闭accept返回的套接字将导致它所代表的连接被关闭,但不会影响服务器 的监听

ü 做客户端时

 
 
阅读(847) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~