socket通信 bind() 函数详解

一.函数解释

在这里插入图片描述

1.函数的作用:

  服务端用于将把用于通信的地址和端口绑定到 socket 上。所以可以猜出,这个函数的参数应该包含:用于通信的 socket 和服务端的 IP 地址和端口号。ip地址和端口号是放在 socketaddr_in 结构体里面的。

2.函数的声明:

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

  (1)参数 sockfd ,需要绑定的socket。

  (2)参数 addr ,存放了服务端用于通信的地址和端口。

  (3)参数 addrlen ,表示 addr 结构体的大小

  (4)返回值:成功则返回0 ,失败返回-1,错误原因存于 errno 中。如果绑定的地址错误,或者端口已被占用,bind 函数一定会报错,否则一般不会返回错误。

3.服务端示例代码

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
 
int main(int argc,char *argv[])
{
  if (argc!=2)
  {
    printf("Using:./server port\nExample:./server 5005\n\n"); return -1;
  }
 
  // 第1步:创建服务端的socket。
  int listenfd;
  if ( (listenfd = socket(AF_INET,SOCK_STREAM,0))==-1) { perror("socket"); return -1; }
 
  // 第2步:把服务端用于通信的地址和端口绑定到socket上。
  struct sockaddr_in servaddr;    // 服务端地址信息的数据结构。
  memset(&servaddr,0,sizeof(servaddr));
  servaddr.sin_family = AF_INET;  // 协议族,在socket编程中只能是AF_INET。
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);          // 任意ip地址。
  //servaddr.sin_addr.s_addr = inet_addr("192.168.190.134"); // 指定ip地址。
  servaddr.sin_port = htons(atoi(argv[1]));  // 指定通信端口。
  if (bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) != 0 )
  { perror("bind"); close(listenfd); return -1; }
 
  // 第3步:把socket设置为监听模式。
  if (listen(listenfd,5) != 0 ) { perror("listen"); close(listenfd); return -1; }
 
  // 第4步:接受客户端的连接。
  int  clientfd;                  // 客户端的socket。
  int  socklen=sizeof(struct sockaddr_in); // struct sockaddr_in的大小
  struct sockaddr_in clientaddr;  // 客户端的地址信息。
  clientfd=accept(listenfd,(struct sockaddr *)&clientaddr,(socklen_t*)&socklen);
  printf("客户端(%s)已连接。\n",inet_ntoa(clientaddr.sin_addr));
 
  // 第5步:与客户端通信,接收客户端发过来的报文后,回复ok。
  char buffer[1024];
  while (1)
  {
    int iret;
    memset(buffer,0,sizeof(buffer));
    if ( (iret=recv(clientfd,buffer,sizeof(buffer),0))<=0) // 接收客户端的请求报文。
    {
       printf("iret=%d\n",iret); break;  
    }
    printf("接收:%s\n",buffer);
 
    strcpy(buffer,"ok");
    if ( (iret=send(clientfd,buffer,strlen(buffer),0))<=0) // 向客户端发送响应结果。
    { perror("send"); break; }
    printf("发送:%s\n",buffer);
  }
 
  // 第6步:关闭socket,释放资源。
  close(listenfd); close(clientfd);
}

二.端口问题

  1.端口用了一次,还没有释放再用这个端口,出现被占用的情况。
在这里插入图片描述

  (1)使用5002端口没有释放
在这里插入图片描述
  (2)再使用一次5002端口,提示端口已经被占用
在这里插入图片描述

  2.socket网络编程中,用于监听的端口范围是多少?默认的端口范围是 0-65535

  (1)1024以下的端口 (是系统保留的),普通用户没有权限。root用户可以
在这里插入图片描述

  (2)1024(包括1024)以上的端口,都可以使用
在这里插入图片描述

三.服务端 socket 的 SO_REUSEADDE 属性

  1.服务端程序的端口释放后可能会处于 TIME_WAIT 状态(等待),要等待两分钟后才能被再次使用,

解决方法:设置 SO_REUSEADDE 选项,让端口释放后立即可以被再次使用。

  2.设置 SO_REUSEADDE 选项,把这段代码写入服务端程序。

int opt = 1; unsigned int len = sizeof(opt);
setsockopt(listenfd,SOL_SOCKET,REUSEADDR,&opt,len);

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值