1.套接字的可选项
2.相关函数
#include
// 功能:获取套接字可选项的信息
// 参数:
// sock--用于查看选项套接字文件描述符
// level--要查看的可选项的协议层
// optname--要查看的可选项名
// optval--保存要查看结果的缓冲地址值
// optlen--向第四个参数 optval 传递的缓冲大小。调用函数后,该变量中保存通过第四个参数返回的可选项信息的字节数
// 返回值:成功时返回 0,失败时返回 -1
int getsockopt(int sock, int level,int optname, void* optval, socklen_t* optlen);
#include
// 功能:设置套接字可选项
// 参数:
// sock--用于更改可选项的套接字文件描述符
// level--要更改的可选项协议层
// optname--要更改的可选项名
// optval--保存要更改的选项信息的缓冲地址值
// optlen--向第四个参数 optval 传递的可选项信息的字节数
// 返回值:成功时返回 0,失败时返回 -1
int setsockopt(int sock, int level, int optname, const void* optval, socklen_t optlen);
3.获取 sock_type
#include
#include
#include
#include
void error_handling(char* message) {
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
int main(int argc, char* argv[]) {
int tcp_sock, udp_sock;
int sock_type;
socklen_t optlen = sizeof(sock_type);
tcp_sock = socket(PF_INET, SOCK_STREAM, 0);
udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
printf("SOCK_STREAM: %d \n", SOCK_STREAM);
printf("SOCK_DGRAM: %d \n", SOCK_DGRAM);
int state = getsockopt(tcp_sock, SOL_SOCKET, SO_TYPE, (void*)&sock_type, &optlen);
if (state)
error_handling("getsockopt() error!");
printf("Socket type one: %d \n", sock_type);
state = getsockopt(udp_sock, SOL_SOCKET, SO_TYPE, (void*)&sock_type, &optlen);
if (state)
error_handling("getsockopt() error!");
printf("Socket type two: %d \n", sock_type);
return 0;
}
运行结果:sock_type 只能获取,不能设置;套接字类型只能在创建时指定,不能修改。
4.获取并修改套接字缓冲大小
#include
#include
#include
#include
void error_handling(char* message) {
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
int main(int argc, char* argv[]) {
int sock;
int snd_buf, rcv_buf;
sock = socket(PF_INET, SOCK_STREAM, 0);
socklen_t len = sizeof(snd_buf);
int state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, &len);
if (state)
error_handling("getsockopt() error");
len = sizeof(rcv_buf);
state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, &len);
if (state)
error_handling("getsockopt() error");
printf("Default input buffer size: %d \n", rcv_buf);
printf("Default output buffer size: %d \n", snd_buf);
snd_buf = 1024 * 3;
rcv_buf = 1024 * 3;
state = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, sizeof(rcv_buf));
if (state)
error_handling("setsockopt() error");
state = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, sizeof(snd_buf));
if (state)
error_handling("setsockopt() error");
len = sizeof(snd_buf);
state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&snd_buf, &len);
if (state)
error_handling("getsockopt() error");
len = sizeof(rcv_buf);
state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&rcv_buf, &len);
if (state)
error_handling("getsockopt() error");
printf("After setting, input buffer size: %d \n", rcv_buf);
printf("After setting, output buffer size: %d \n", snd_buf);
return 0;
}
运行结果:设置的IO缓冲大小和指定的3K不一致,这个是由系统自动调整的
5.Time-wait 状态
6.Time-wait 状态下的端口号再分配,修改 SO_REUSEADDR 选项
#include
#include
#include
#include
#include
#include
void error_handling(char* message) {
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
int main(int argc, char* argv[]) {
int serv_sock, clnt_sock;
struct sockaddr_in serv_addr, clnt_addr;
char message[30];
if (argc != 2) {
printf("Usage : %s \n", argv[0]);
exit(1);
}
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
if (serv_sock == -1)
error_handling("socket() error");
int option = 1;
socklen_t optlen = sizeof(option);
setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void*)&option, optlen);
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(argv[1]));
if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
error_handling("bind() error");
if (listen(serv_sock, 5) == -1)
error_handling("listen() error");
socklen_t clnt_addr_size = sizeof(clnt_addr);
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if (clnt_sock == -1)
error_handling("accept() error");
int str_len;
// 收到客户端的消息后,将消息回送给客户端
while ((str_len = read(clnt_sock, message, sizeof(message))) != 0) {
write(clnt_sock, message, str_len);
write(1, message, str_len);
}
close(clnt_sock);
close(serv_sock);
return 0;
}
运行结果:可以看出,即使服务器端强行结束程序,立即重新执行程序,没有报错
7.Naggle算法
参考书籍:《TCP/IP网络编程》尹圣雨 著,金果哲 译