#include <sys/types.h>
#include <sys/socket.h>
1、创建套接字
int socket(int domain,int type,int protocol);
domain:AF_INET/AF_INET6/AF_UNIX
type:SOCK_STREAM(流式协议,默认是tcp)/SOCK_DGRAM(报式协议,默认是udp)
protocol:传0表示使用默认协议,即tcp,,,,udp..
成功:返回创建的文件描述符,失败返回-1,errno查看具体错误
if(fd < 0)
{
if((errno == EINTR) || (errno == EAGAIN))
{
printf("*********");
return -1;
}
}
socket相当于普通文件的open函数
socket中的第一个参数AF_INET 和sock_addr.sin_family = AF_INET;地址族协议一定是一样的。
2、int bind(int sockfd,const struct sockaddr *addr, socklen_t addrlen);
addrlen是addr的大小
成功:返回创建的文件描述符,失败返回-1,errno查看具体错误
服务器端使用bind函数,
客户端一般不用bind函数,系统会自动分配给客户端端口号,当然客户端也可以显示调用bind,使用固定的ip 和端口号,但是对socket通信没有影响,所以,客户端程序一般不写bind函数。
3、listen//用来指定同时允许多少个客户端建立连接,即处于tcp三次握手过程的客户端数
int listen(int sockfd,int backlog);
backlog:排队建立3次握手队列和刚刚建立3次握手队列的链接和数
成功返回0,失败返回-1
//一般listen(fd,128);//一般取上限128
假设同时此时有128个客户端来请求建立连接,又有一个客户端请求连接,则必须等待某个客户端三次握手完成,这个客户端才能开始建立连接:
注意:这个不是指所能连接的客户端数,而是指正在连接的客户端上限。
4、accept//
addr:返回链接客户端地址信息,传出参数,不需要初始化。
addrlen:是个传入传出参数,传入的是容器的大小,传出的是改变后的大小
成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errno
即返回的这个文件描述符才是与客户端成对存在的那个socket
struct sockaddr_in clie_addr;
socklen_t clie_addr_len = sizeof(clien_addr);
cfd = accept(lfd,&clie_addr,&clie_addr_len);
//clie_addr_len是个传入传出参数,所以需要将clie_addr_len先赋值再传入
accept调用后,会在此阻塞等待。
5、connect
int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
成功:返回创建的文件描述符,失败返回-1,errno查看具体错误
注意:上图中,accept在没有客户端连接的时候,会发生阻塞,select() 函数则不会阻塞。
另外,客户端也可以调用bind()函数,绑定自己的ip和端口号,但是这个不是必须的。默认不写的话,会给其自动分配。
最后要close是因为,socket也是个文件,open之后要进行关闭。
小结:bind()、accept()、connect()三个函数中的addr都需要进行struct sockaddr_in强制类型转换struct sockaddr。
自定义的端口号,不能超过65536,并且<1000的,一般是系统占用了,我们一般使用3000以上的端口号。
另, read和write函数参看 :https://blog.youkuaiyun.com/modi000/article/details/105650080