话说今儿个咱来聊聊socket编程里头的bind()这玩意儿。作为一个老网虫,当年刚开始捣鼓网络编程的时候,那可真是两眼一抹黑。就知道写个服务器端程序,得先弄个socket(),然后bind()一下,再listen(),才能accept()客户端的连接,才能recv()收数据。那时候,只知道要这么干,至于为还真没深究过。
今儿个咱就从头到尾,把这个bind()给掰扯清楚。咱也不是啥学院派,就按咱自个儿折腾的经验来。
从零开始
咱就是照猫画虎,跟着网上的教程一步步来。先用socket()整出一个“套接字”来,这玩意儿就像个电话插座,有它才能跟别人通上话。
然后,就是这个bind()。那时候的理解,就是把这个“插座”给固定到一个“房间号”和“门牌号”上。这个“房间号”就是端口号(port),“门牌号”就是IP地址。这样,别人才能找上门来。
那时候的代码,大概长这样(这是简化过的):
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// ... 填充 sockaddr_in 结构体 ...
bind(sockfd, (struct sockaddr )&server_addr, sizeof(server_addr));
// ... listen, accept, 等等 ...
遇到问题
这么写,大多数时候是没啥问题的。但是,折腾久,总会遇到点“幺蛾子”。
比如,有时候重启程序,会提示“Address already in use”。啥意思?就是说,你这个“房间”已经被别人占。这可咋整?
后来经过一番“百度”(那时候还不太流行“谷歌”),才知道,原来是端口没释放干净。程序退出,但是端口可能还被系统占用着。得想办法让它赶紧腾地方。
解决问题
解决办法也简单,就是在bind()之前,设置一下socket的选项,让它支持端口重用。代码大概是这样:
int optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
加上这两行,再重启程序,就没问题。那时候觉得,这玩意儿真神奇!
更深入的理解
再后来咱的“功力”也见长,对bind()的理解也更深一层。
bind()不仅仅是绑定端口那么简单。它还做这些事:
- 检查端口是否可用: 看看你选的这个“房间”是不是空的,有没有被别人占用。
- 绑定IP地址: 如果你的机器有多个“门牌号”(多个网卡),你可以指定只监听某个“门牌号”。如果不指定,那就是“0.0.0.0”,表示监听所有“门牌号”。
- 告诉系统: 跟操作系统说一声,这个“插座”归我,别人要打这个“房间”的电话,都转到我这里来。
而且咱还知道,服务器程序一般都得bind()一个固定的端口,比如HTTP服务的80端口,HTTPS服务的443端口。这样,客户端才能知道往哪儿连。
总结
所以说,这个bind(),别看它就一行代码,里头的水还挺深。从一开始的“照猫画虎”,到后来的“知其所以然”,这也是咱一路折腾过来的经验。写程序嘛就是这样,得多动手,多踩坑,才能真正弄明白。
今儿个就分享到这儿,希望对刚入门的小伙伴们有点帮助。记住,实践出真知!