1.基于Ubuntu系统
1) socket描述符类型 int
2)结构体:sockaddr_in
struct sockaddr_in {
short int sin_family; /* 通信类型 */
unsigned short int sin_port; /* 端口 */
struct in_addr sin_addr; /* Internet 地址 */
unsigned char sin_zero[8]; /* 与sockaddr结构的长度相同*/
};处理套接字地址。
3)本机转换
htons()--"Host to Network Short"
htonl()--"Host to Network Long"
ntohs()--"Network to Host Short"
ntohl()--"Network to Host Long"
4)端口号选择
不要采用小于 1024的端口号。所有小于1024的端口号都被系统保留!你可以选择从1024 到65535的端口
5)socket()函数
int server_sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if(server_sock_fd == -1)
{
perror("socket error");
return 1;
}
6)bind()函数
将套接字和机器上的端口关联。
int bind_result = bind(server_sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(bind_result == -1)
{
perror("bind error");
return 1;
}
7)listen()函数,等待接入请求,并用各种方法处理它。
if(listen(server_sock_fd, BACKLOG) == -1)
{
perror("listen error");
return 1;
}
backlog 是在进入 队列中允许的连接数目。 大多数系统的允许数目是20,你也可以设置为5到10。
8)accept()函数
你可以想象发生 这样的事情:有人从很远的地方通过一个你在侦听 (listen()) 的端口连接 (connect()) 到你的机器。它的连接将加入到等待接受 (accept()) 的队列 中。你调用 accept() 告诉它你有空闲的连接。它将返回一个新的套接字文 件描述符!这样你就有两个套接字了,原来的一个还在侦听你的那个端口, 新的在准备发送 (send()) 和接收 ( recv()) 数据。这就是这个过程!
addr 是个指 向局部的数据结构 sockaddr_in 的指针。
int accept(int sockfd, void *addr, int *addrlen);
具体使用:
struct sockaddr_in client_address;
socklen_t address_len = sizeof(client_address);
int client_sock_fd = accept(server_sock_fd, (struct sockaddr *)&client_address, &address_len);
9)send()函数和recv()函数
int send(int sockfd, const void *msg, int len, int flags);
sockfd 表示你想要发送数据的套接字描述符,可以为socket() 或者是 accept() 返回的的返回值。
msg 发送数据的指针
len 发送数据的长度
flags 设置为 0
int recv(int sockfd, void *buf, int len, unsigned int flags);
sockfd表示要读的套接字描述符。buf表示要读的信息缓冲,len表示缓冲的最大长度,flags置为0。
recv返回的为实际读入缓冲的数据的字节数。在错误的时候,返回-1.
10)select()多路同步
假设这样的情况:你是个服 务器,你一边在不停地从连接上读数据,一边在侦听连接上的信息。 没问题,你可能会说,不就是一个 accept() 和两个 recv() 吗? 这么 容易吗,朋友? 如果你在调用 accept() 的时候阻塞呢? 你怎么能够同时接 受 recv() 数据? “用非阻塞的套接字啊!” 不行!你不想耗尽所有的 CPU 吧? 那么,该如何是好?
select() 让你可以同时监视多个套接字。如果你想知道的话,那么它就 会告诉你哪个套接字准备读,哪个又准备写,哪个套接字又发生了例外 (exception)。