socket
结构体
sockaddr
struct sockaddr{
sa_family_t sin_family;
char sa_data[14];
}
sockaddr_in 是为了保存ipv4地址信息的结构体
struct sockaddr_in{
sa_family_t sin_family; //地址族
uint16_t sin_port; //16位tcp/udp端口
struct in_addr sin_addr; //32位ip地址
char sin_zero[8]; //不适用
}
- 使用时是在,bind,accept,connect中通过(SOCKADDR*)强制转换
struct in_addr{
in_addr_t s_addr; //32位ipv4地址
}
数据类型 说明 头文件
uint16_t unsinged long(32-bit) sys/types.h
sa_family 地址族(adress family) sys/socket.h
socklen_len 长度 sys/socket.h
in_addr_t ip地址(uint32_t) netinet/in.t
in_port_t 端口地址(uint16_t) netinet/in.t
sin_family
- AF_INET --------------------------------------IPV4使用的地址族
- AF_INET6----------------------------------------IPV6使用的地址族
- AF_LOCAL----------------------------------------本地通信中采用UNIX协议的地址族
sin_port
- 保存16位端口号
sin_zero
- 无特殊意义,只是为了让 sockaddr_in和sockaddr保持一致
字符序转换
主机字节序和网络字节序的转换
unsigned short htons(unsigned short);
unsigned short ntons(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntonl(unsigned long);
//理论上大端序不用更换成网络号
- htons中的h表示主机(host)字序转换成网络字节序
- ntons中的n表示网络(network)字节序转换成主字节序
字符串和整型的网络字节序的转换
#include<arpa/inet.h>
in_addr_t inet_addr(const char *string)
//成功时返回32位整数型,失败时返回INADDR_NONE
#include<arpa/inet.h>
int inet_aton(const char* string,struct in_addr *addr) //将改变的值存入addr中
//成功时返回1,失败是返回0
相反
#include<arpa/inet.h>
char * inet_nota(struct in_addr adr);
//成功时返沪转换的字符串地址值,失败时返回-1
Windows服务端
区别于Liunx
- 通过WSAStartup,WSACleanup函数初始化并清除套接字相关库
- 把数据类型和变量名切换成Windows风格
- 数据传输用recv,send函数,而不是read,write函数
- 关闭套接字时用closesocket函数,而不是close函数
利用WSAStarup,WSACleanup函数初始化并清除套接字相关库
#include<winsock2.h>
WSADATA wasdata;
if(WSAStarup(MAKEWORD(2,2),&wsaData)!=0)
ErrorHandling("WSAStarup() error!");
创建套接字
#include<winsock.h>
SOCKET socket(int af,int type,int protocol);
//成功时返回套接字句柄,失败时返回INVALID_SOCKET;
调用:
SOCKET hServSock = socket(PF_INET,SOCK_STREAM,0);
if(hServSock == INVALID_SOCKET)
ErrorHanding("socket() error!");
连接自身ip和端口号
#include<winsock.h>
int bind(SOCKET s,const struct sockaddr *name,int namelen);
//成功返回0,失败返回SOCKET_ERROR
调用
SOCKADDR_IN servAdr;
memset(&servAdr,0,sizeof(servAdr));
servAdr.sin_family = AF_INET;
servAdr.sin_addr.s_addr = htonl(INADDR_ANY); //区别于客户端的connect,这里的ip是直接自动获取的
servAdr.sin_port = htons(atoi(argv[1]));
if(bind(hServSock,(SOCKADDR*)&sercAdr,sizeof(servAdr))==SOCKET_ERROR)
ErrorHandling("");
监听
#include<winsock.h>
int listen(SOCKET s,int backlog);
//成功返回0,失败返回SOCKET_ERROR
调用
if(listen(hServSock,5)==SOCKET_ERROR)
ErrorHandling("");
等待连接
#include<winsock.h>
int accept(SOCKET s,struct sockaddr * addr,int *addrlen);
//成功返回套接字句柄,失败返回TNVALID_SOCKET
调用
SOCKADDR_IN clntAdr;
SOCKAT hClntSock;
int clntAdrsize;
clntAdrSize = sizeof(clntAdr);
hClntSock = accept(hServSock,(SOCKADDR*)&clntAdr, &clntAdrSize);
Windows客户端
#include<winsock.h>
int connect(SOCKET s,const struct sockaddr* name,int namelen);
//成功返回0,失败返回SOCKET_ERROR
调用
- 除了函数名和ip获取方式,其余和服务端bind 一模一样
SOCKADDR_IN servAdr;
memset(&servAdr,0,sizeof(servAdr));
servAdr.sin_family = AF_INET;
servAdr.sin_addr.s_addr = inet_addr(argv[1]); //区别于服务端的bind,这里的IP是输入的
servAdr.sin_port = htons(atoi(argv[2]));
if(connect(hServSock,(SOCKADDR*)&sercAdr,sizeof(servAdr))==SOCKET_ERROR)
ErrorHandling("");
关闭套接字
#include<winsock.h>
int closesocket(SOCKET s);
//成功时返回0,失败时返回SOCKET_ERROR
发送
#include<winsock2.h>
int send(SOCKET s,const char *buf,int len,int flags);
//成功时返回传出字节数,失败时返回SOCKT_ERROR
接受
#include<winsock2.h>
int recv(SOCKET s,const char* buf,int len,int flags);
//成功时返回收到的字节数(收到EFO时为0),失败时返回SOCKET_ERROR
UDP区别于TCP的地方
发送
#include<winsock2.h>
int sendto(int sock,void *buff,size_t nbytes,int flags,struct sockaddr *to,int tolen);
//成功时返回传输的字节数,失败时返回SOCKET_ERROR
- sock:用于传输数据的udp套接字文件描述符
- buff:保存待传数据的缓冲地址值
- nbytes:待传输的数据长度,以字节为单位
- flags:可选项参数,若没有则传递0
- to:存有目标地址信息的sockaddr结构体变量的地址值
- addrlen:传递给参数to的地址值结构体变量长度
接受
#include<winsock2.h>
int sendto(int sock,void *buff,size_t nbytes,int flags,struct sockaddr *to,int tolen);
//成功时返回收到的字节数,失败时返回SOCKET_ERROR
-
基本同上
-
如果一个udp套接字connect到了一个目标套接字,那么就不能再给其他套接字发送消息
Liunx服务端
创建套接字
#include<sys/socket.h>
int socket(int domain,int type,int protocol);
//成功返回文件描述符,失败返回-1
连接自身ip和端口号
#include<sys/socket.h>
int socket(int sockfd,struct sockaddr *myaddr,socklen_t addrlen);
//成功返回0,失败返回-1
监听
#include<sys/socket.h>
int listen(int sockfd,int backlog);
//成功返回0,失败返回-1
等待连接
#include<sys/socket.h>
int accept(int sockfd,struct sockaddr *addr,socklen_t addrlen);
//成功返回文件描述符,失败返回-1
Liunx客户端
#include<sys/socket.h>
int connect(int sockfd,struct sockaddr *serv_addr,socklen_t addrlen);
//成功返回0,失败返回-1
文件读取
打开文件
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int open(const char* path,int flag);
//成功时返回文件描述符,失败时返回-1
//path:文件名的字符串地址
//文件打开模式
打开模式
- O_CREAT--------------------------------------------------------------------必要时创建文件
- O_TRUNC--------------------------------------------------------------------删除全部现有数据
- O_APPEND------------------------------------------------------------------维持现有数据,保存在后面
- O_RDONLY------------------------------------------------------------------只读打开
- W_WRONLY-----------------------------------------------------------------只写打开
- O_RDWR----------------------------------------------------------------------读写打开
调用
#include<>
关闭文件
#include<unistd.h>
int close(int fd);
//成功时返回0,失败时返回-1
- fd,要关闭的文件或套接字的文件描述符
将数据写入文件
#include<unistd.h>
ssize_t write(int fd,const void * buf,size_t nbytes);
//成功时返回要写入的字节数,失败时返回-1
- fd: 显示数据传输对象的文件描述符
- buf:保存要传输数据的缓冲地址值
- nbytes:要传输数据的字节数
读取文件中的数据
#include<unistd.h>
ssize_t read(int fd,void * buf,size_t nbytes);
//成功时返回收到的字节数(但遇到文件结尾则返回0),失败时返回-1
- fd:显示数据接收对象的文件描述符
- buf:要保存接收数据的缓冲地址值
- nbytes:要接受数据的最大字节数
UDP区别于TCP的地方
发送
#include<sys/socket.h>
ssize_t sendto(int sock,void *buff,size_t nbytes,int flags,struct sockaddr *to,socklen_t addrlen);
//成功时返回传输的字节数,失败时返回-1
- sock:用于传输数据的udp套接字文件描述符
- buff:保存待传数据的缓冲地址值
- nbytes:待传输的数据长度,以字节为单位
- flags:可选项参数,若没有则传递0
- to:存有目标地址信息的sockaddr结构体变量的地址值
- addrlen:传递给参数to的地址值结构体变量长度
接受
#include<sys/socket.h>
ssize_t sendto(int sock,void *buff,size_t nbytes,int flags,struct sockaddr *to,socklen_t addrlen);
//成功时返回收到的字节数,失败时返回-1
- 基本同上