Linux下socket编程学习

相关结构

//下边这两个结构定义在<sys/types.h>里
//一般的地址结构,只能用于覆盖(把其他地址转换为此类型),且只能引用该地址的sa_family字段
 struct sockaddr
    {
    unsigned char sa_len;   //total length,整个结构体的长度,旧版本没有
    unsigned short  sa_family;   //地址族
    char    sa_data[14];   //地址的值
  
  //TCP/IP使用的地址结构
struct sockaddr_in
    {
       unsigned char    sin_len;    //total length
       short int                     sin_family;   //地址族,一般为AF_INET(ipv4),ipv6为(AF_INET6)
       unsigned short int      sin_port;      //端口号
       struct in_addr             sin_addr;      //ip地址
       char             sin_zero[8];  //没有使用(设置为0)
    }

相关函数-主调用

如果函数调用失败,都返回-1,调用失败会在全局变量error里有相应的值
不涉及到读取、发送的时候,调用正常都返回0

socket()

创建套接字

int socket(int family, int type, int protocol)

family: 协议或地址族,TCP/IP为PF_INET,(ipv6为PF_INET6),也可以使用AF_INET
type: 套接字类型

  • 流式套接字:SCOK_STREAM, TCP
  • 数据报套接字:SOCK_DGRAM,UDP
  • 原始套接字:SOCK_RAW,没有经过处理的IP数据包,可以根据自己程序的要求进行封装

protocol:用来指定socket所使用的传输协议编号,通常设为0即可。

调用成功返回描述符

connect()

为套接字指明远程端点的地址。为TCP时,connect使用三次握手建立连接;为UDP时,connect仅指明远程端点,但是不向他发送任何数据

int connect(int sock, struct sockaddr \*serv_addr, int addrlen)

sock: 目的服务器的socket描述符
serv_addr:包含目的机器ip地址和端口号的指针
addrlen:sizeof(struct sockaddr)
调用成功返回0

send()/write() -TCP

linux下可以使用write(),将报文传递给目标主机

(int sock, char\* msg, int msglen, int flags);

flags:控制bit,指明是否接受带外数据和是否预览报文,一般为0

write(int sock, char* buf,  int buflen)

buf:含有数据缓存的地址
buflen:buf中的字节数
这两个函数调用成功时都返回传送的字节数

recv()/read() -TCP

从套接字中接收数据

nt recv(int sock, char\* buf, int len, int flags)

buf:存放数据的缓存地址
len:缓存的长度
flags:控制bit,指明是否接受带外数据和是否预览报文一般为0

read(int sock, char* buf,  int buflen)

调用成功都返回读取的字节数

sendto() -UDP

从一个结构中获取目的地址,然后发送报文

int sendto(int sock, char \*msg, int msglen, int flags, const struct sockaddr\* to, int\* tolen);

tolen:地址结构的字节长度
成功时,返回已发送的字节数

recvfrom() -UDP

从套接字获取下一个传入报文,并记录发送者的地址

int recvfrom(int sock, char\* buf, int buflen, int flags, struct sockaddr\* from, int\* fromlen)
 ```
fromlen:缓存的长度,返回时为发送者地址的大小。
成功调用时,返回报文中的字节数

### bind()
主要由服务器使用,指明本地ip地址和协议端口号

int bind(int sock, struct sockaddr *localaddr, int addrlen)

成功时返回0

### listen() -TCP
服务器调用,使套接字处于被动状态(准备接受传入请求)

int listen ( sock,queuelen)

queuelen:传入链接请求的队列大小(通常最大不超过5)

### accept() -TCP
bind->listen->accept,从队列中取走下一个链接请求(或者一直在那里等待下一个连接请求到来),为请求创建新套接字,并返回新套接字描述符。

int accept(int sock, struct sockaddr * addr, int* addrlen)

addrlen:初始指明为addr的大小,调用返回时为存储在addr中的字节数

### close()
终止通信,删除套接字,任何正在套接字上等待被读取的数据都将被抛弃。  
linux使用了引用计数机制,可以多个进程共享一个套接字。close每被调用一次,引用计数减1,引用计数为0时才释放。

int close(int sock)

成功时返回0

### shutdown()
部分关闭连接

int shutdown(int sock,int direction )

direction:0,终止进一步输入;1,终止进一步输出;2,终止输入和输出

## 辅助函数
### 整数转换
TCP/IP协议首部使用的二进制采用网络字节顺序(表示整数时,最高字节在前)  
为了机器和网络字节顺序兼容,应当始终调用转换函数

htons(host to network short)
ntohs
htonl
ntohl

### 地址转换inet_addr
接受字符串(点分十进制),返回等价二进制表示的地址

serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
```

查找域名对应ip地址gethostbyname

接收ASCII字符串域名,返回hostent结构,定义在<netdb.h>

struct hostent
{
    char*    h_name,    //正式主机名
    char**   h_aliases, //其他别名列表
    int      h_addrtype,    //地址类型
    int      h_length,  //地址长度
    char**   h_addr_list    //一般主机可以有多个ip地址,h_addr_list用来
保存多个ip地址
}
#define h_addr h_addr_list[0]   //为了与早期的版本兼容

由服务名字得到熟知端口getservbyname

成功则返回一个servent结构指针,发生差错就返回空指针,结构定义在<netdb.h>

servent* getservbyname(char\* name, char\* proto)

struct servent
{
char* s_name; //正式服务名
char** s_aliases; //其他别名列表
int s_port; //该服务使用的端口
char *s_proto; //服务器所用的协议
};
```

根据协议名找到该协议的正式整数值getprotobyname(char* name)

成功就返回protoent结构指针,结构定义在<netdb.h>

struct protoent
{
    char\*      p_name; //协议正式名
    char\*\*    p_aliases;  //协议的别名列表
    int         p_proto;        //正式协议名
}

获取主机名字gethostname

以字符串形式返回主机名

int gethostname(char\* name, namelen)

name:放置名字的字符数组的地址

获取远程端点地址getpeername

需要已经建立链接

int getpeername(int sock, sockaddr\* remaddr, int\* addrlen)

remaddr:含有对端地址的sockaddr指针
addrlen:调用前为第二个参数的长度,调用后为远程端点地址的实际长度

设置/查看套接字参数

相关推荐