socket选项
特意用来读取和设置socket文件描述符属性的方法:
#include<sys/socket.h>
int getsockopt(int sockfd,int level, int option_name,void* option_value,socklen_t* restrict option_len);
int setsockopt(int sockfd, int level, int option_name,const void* option_value,sockelen_t option_len);
参数解释:sockfd指定了被操作的目标socket;level参数指定了要操作的协议的选项,比如IPV4,IPV6,TCP等;option_name指定了选项的名字;option_value和option_len分别表示被操作项的值和长度。这两个函数调用成功时返回0,失败时返回-1,并设置errno
下表中列出了比较常用的socket选项,不同的选项具有不同类型的值:
sol_socket下的SO_REUSEADDR
通过socket选项SO_REUSEADDR强制使用被处于TIME_WAIT状态的连接占用的socket地址。代码如下:
int sock =socket(PF_INET,SOCK_STREAM,0);
assert(sock != -1);
int reuse = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
struct sockaddr_in addresss;
bzero(&address,sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INT,ip,&address.sin_addr);
address.port = htons(port);
bind(sock,(struct sockaddr* )&address,sizeof(address));
可以使处于TIME_WAIT状态的socket地址被立即重用。
SOL_SOCKET 下的SO_RCVBUF和SO_SNDBUF
这两个选项分别表示了接收缓冲区和发送缓冲区的大小。用setsockopt设置接收和发送缓冲区的大小时,系统会自动将其值加倍,并且不得小于某个值;这样做,是为了TCP接收数据时有足够的缓冲区处理拥塞。
以下是一对客户端和服务器程序,分别修改了TCP发送缓冲区和接收缓冲区的大小。
修改TCP发送缓冲区的客户端程序
#include<sys/socket.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
#define buffer 512
int main(int argc, char* argv[])
{
if(argc <= 2)
{
cout<<"usage :"<<base(argv[0])<<"ip address port_number send_buffer_size"<<endl;
return 1;
}
const char* ip = argv[1];
int port = atoi(argv[2]);
struct sockaddr_in server_address;
bzero(&server_address,sizeof(server_address));
server_address.sin_family = AF_INET;
inet_pton(AF_INET,ip,&server_address.sin_addr);
server_address.sin_port = htons(port);
int sock = socket(PF_INET,SOCK_STREAM,0);
assert(sock = -1);
int sendbuf = atoi(argv[3]);
int len = sizeof(sendbuf);
setsockopt = (sock,SOL_SOCKET,SO_SNDBUF,&sendbuf,sizeof(sendbuf));
getsockopt = (sock,SOL_SOCKET,SO_SNDBUF,&sendbuf,(socklen_t*) &len);
cout<<"the tcp buffer size after setting is "<<sendbuf<<endl;
if(connect(sock, (struct sockaddr* )&server_address,sizeof(server_address)) !=-1)
{
char Buffer[buffer];
memset(Buffer,'a',buffer);
send(sock,Buffer,buffer,0);
}
close(sock);
return 0 ;
}
修改TCP接收缓冲区的服务器程序
#include<sys/socket.h>
#include<netinet.h>
#include<arpa/inet.h>
#include<assert.h>
#include<cstdio>
#include<unistd.h>
#include<cstdlib>
#include<errno.h>
#include<cstring>
using namspace std;
#defing BUFFER_SIZE 1024
int main()
{
if (argc <= 2)
{
cout<<"usage:"<<basename(argv[0])<<"ip_address port_number recv_beffer_size"<<endl;
return 1;
}
const char* ip = argv[1];
int port = atoi(argv[2]);
struct sockaddr_in address;
bzero(&address,sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET,ip,&address.sin_addr);
address.sin_port = htons(port);
int sock = socket(PF_INET,SOCK_STREAM,0);
assert(sock != -1);
int recvbuf = atoi(argv[3]);
int len =sizeof(recvbuf);
setsock(sock, SOL_SOCKET,SO_RCVBUF,&recvbuf,sizeof(recvbuf));
getsock(sock,SOL_SOCKET,SO_RCVBUF,&recvbuf,(socklen_t*)&len);
cout<<"the TCP receive buffer size after setting is"<<recvbuf<<endl;
int ret = bind(sock,(struct sockaddr*)&address,sizeof(address));
assert(ret != -1);
ret =listen(sock,5);
assert(ret != -1);
struct sockaddr_in client;
socklen_t client_addrlength = sizeof(client);
int connfd = accept(sock,(struct sockaddr*)&client,&client_addrlength);
if(connfd < 0 )
{
cout<<"errno is"<<errno<<endl;
}
else
{
char buffer[BUFFER_SIZE];
memset(buffer,'\0',BUFFER_SIZE);
while(recv(connfd,buffer,BUFFER_SIZE - 1,0)>0){}
close(connfd);
}
close(sock);
return 0;
}