一.网络编程的基本过程(windows)
1.调用socket函数创建套接字
2.调用bind函数分配IP地址和端口号
3.调用listen函数转为可接收请求。
4.调用accept函数受理连接请求。
5.数据的发送和接收
6.客户端的请求连接
7.关闭套接字
1.创建套接字
socket(int af,int type,int protocol); //成功返回套接字句柄,失败返回INVALID_SOCKET
af为协议族:PF_INET 为ipv4互联网协议族,PF_INET6为IPv6互联网协议族。目前普遍使用ipv4。
type为:面向连接的套接字(SOCK_STREAM),面向消息的套接字(SOCK_DGRAM)。
一般情况下protocol可以传递0,除非遇到同一协议族中存在多个数据传输方式相同的协议。例如:TCP协议IPPROTO_TCP ,UDP协议为IPPROTO_UDP。
2.进行绑定
bind(SOCKET s,struct sockaddr *name,int addrlen); //成功返回0,失败返回SOCKET_ERROR
addrlen:占内存大小,一般使用sizeof(name)
name:指向含有本机IP地址及端口号的sockaddr类型的指针
struct sockaddr_in{
sa_family_t sin_family; //地址族 IPV4:AF_INET IPV6:AF_INET6
uint16_t sin_port; //16位端口号 ,它以网络字节序保存
struct in_addr sin_addr; //32位IP地址 它以网络字节序保存
char sin_zero[8]; //不使用 必须填充为0
}
其中
struct in_addr
{
In_addr_t s_addr; ///32位IPV4地址。
}
可分配的端口号为:0~65535,其中0~1023是知名端口不可以使用。
注意sin_port和sin_addr需要转换成网络字节序
字节序转换:htons(unsigned short);其中h代表主机字节序,n代表网络字节序,s指的是short,l指的是long,中间用to连接。可以理解为把short型的数据从主机字节序转化为网络字节序。
将字符串信息转为网络字节序的整数型:
inet_addr(const char * string);成功返回32为大端序整数型值,失败时返回INADDR_NONE.还可以检测是否为合理ip地址。
inet_aton函数与inet_addr在功能上完全相同。只是inet_aton利用了in_addr结构体,且其使用频率更高。
inet_ntoa(struct in_addr adr)相反,成功时返回转换后的字符串地址值,失败返回-1;
※ 每次创建服务器端套接字都要输入IP地址会有些繁琐,可以使用INADDR_ANY,如:addr.sin_addr.s_addr=htonl(INADDR_ANY).
※ 普遍使用memset()函数,主要作用是使sockaddr_in结构体中的sin_zero为0。
3.进行监听
listen(SOCKET s,int backlog); // 成功返回0,失败返回SOCKET_ERROR
s 为需要进入监听状态的套接字
backlog 为请求队列的最大长度。
当套接字正在处理客户端请求时,如果有新的请求进来,套接字是没法处理的,只能把它放进缓冲区,待当前请求处理完毕后,再从缓冲区中读取出来处理。如果不断有新的请求进来,它们就按照先后顺序在缓冲区中排队,直到缓冲区满。这个缓冲区,就称为请求队列(Request Queue)。
缓冲区的长度(能存放多少个客户端请求)可以通过 listen() 函数的 backlog 参数指定,但究竟为多少并没有什么标准,可以根据你的需求来定,并发量小的话可以是10或者20。
如果将 backlog 的值设置为 SOMAXCONN,就由系统来决定请求队列长度,这个值一般比较大,可能是几百,或者更多。
当请求队列满时,就不再接收新的请求,对于 Linux,客户端会收到 ECONNREFUSED 错误,对于 Windows,客户端会收到 WSAECONNREFUSED 错误。
※listen() 只是让套接字处于监听状态,并没有接收请求。
4.接收
accept(SOCKET s,struct sockaddr *addr,int *addrlen); // 成功返回套接字句柄,失败返回INVALID_SOCKET
它的参数与 listen() 和 connect() 是相同的。
s为服务器端套接字
addr 为 sockaddr_in 结构体变量
addrlen 为参数 addr 的长度,可由 sizeof() 求得。
accept()返回一个新的套接字来和客服端通信,addr保存了客户端的IP地址和端口号,而s是服务器端的套接字。后面和客户端通信时,要使用这个新生成的套接字,而不是原来服务器端的套接字。
※listen() 只是让套接字进入监听状态,并没有真正接收客户端请求,listen() 后面的代码会继续执行,直到遇到 accept()。accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来。
5.数据的接收与发送
send(SOCKET s,const char * buf,int len,int flags); //成功时返回传输字节数。失败时返回SOCKET_ERROR。
其中s 表示数据传输对象连接的套接字句柄值。
buf 保存待传输数据的缓冲地址值。
len要传输的字节数。
flags传输数据时用到的多种选项信息。一般设置为 0 或 NULL。
recv(SOCKET s,const char * buf,int len,int flags); //成功时返回接收的字节数(收到EOF时为0),失败返回SOCKET_ERROR.
其中s 表示数据接收对象连接的套接字句柄值
buf保存结束数据的缓冲地址值
len表示接收的最大字节数
flags表示接收数据时用到的多种选项信息。
6.客户端的请求连接
connect(SOCKET s,struct sockaddr *serv_addr,int addrlen); // 成功返回0,失败返回SOCKET_ERROR
serv_addr 包含远端主机的IP地址和端口号的指针
addrlen 远端地址结构的长度
对于客户端无需像服务器端一样使用bind()、listen()、accept()函数。
7.关闭套接字
closesocket(SOCKET s); //成功返回0 失败返回SOCKET_ERROR
不管是客户端还是服务器端最后都不要忘记使用closesocket()函数关闭创建的套接字。
原文:https://www.cnblogs.com/ynhay/p/14118012.html