SOCKET网络编程细节问题1
SOCKET网络编程快速上手(二)——细节问题(1)
三、细节问题一个也不能少
Socket编程说简单也简单,程序很容易就能跑起来,说麻烦还真是麻烦,程序动不动就出问题。记得刚开始写网络代码的时候,那真是令人抓狂的经历,问题一个套一个,一会服务器起不来了,一会数据接收异常了,到最后自己都对那些系统调用都不放心了,怎么会要考虑那么多东西?起初,我是一万个怀疑,是不是自己人品出问题了,怎么别人没遇到,全给自己赶上了。后来,拿着《UNIX网络编程》随便看看,那书怎么会这么了解我的?细节!细节!细节!那些问题都被别人明明写出来了,自己又SX了。没办法,细节不注意,有苦说不出啊。
不过也不能怪自己不爱学习啊,说实话那书实在太厚了,下面只记录一些自己遇到的、知道原因和解决方法的细节问题,还有很多后面慢慢学习吧!问题中使用的示例程序多少有点编造的意思,旨在说明问题。现实当中肯定是会发生的,概率也不能说低,我也没那么多闲时去统计具体数据。
端口复用
此处描述的内容可能和端口复用的真实概念不符合,但我习惯用这种描述方法,理解下面内容即可。
在调试网络程序的时候,TCP服务器经常起不来,总是在bind时出错。经验告诉我,此时换一个绑定端口往往就能起效,或者等个几分钟,服务器也能正常启动了。因为当时跑的都是些小的测试代码,换个端口还是很方便的。可这种问题要是放到一个系统或者一个服务器上,怎能接受?
当时,自己摸索了几天都没什么结果,最后还是师傅威武,告诉我还有个端口复用的东西。现在整理,已经没了当时的环境,自己构造了这一问题。
客户端程序为:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <netdb.h>
9
10 #define PORT 1234
11 #define MAXDATASIZE 1000
12
13 int main(int argc, char *argv[])
14 {
15 int sockfd, num;
16 char buf[MAXDATASIZE + 1] = {0};
17 struct sockaddr_in server;
18
19 if (argc != 2)
20 {
21 printf("Usage:%s <IP Address>\n", argv[0]);
22 exit(1);
23 }
24
25 if ((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1)
26 {
27 printf("socket()error\n");
28 exit(1);
29 }
30 bzero(&server, sizeof(server));
31 server.sin_family = AF_INET;
32 server.sin_port = htons(PORT);
33 server.sin_addr.s_addr = inet_addr(argv[1]);
34 if (connect(sockfd, (struct sockaddr *)&server, \
35 sizeof(server)) == -1)
36 {
37 printf("connect()error\n");
38 exit(1);
39 }
40
41 while (1)
42 {
43 memset(buf, 0, sizeof(buf));
44 if ((num = recv(sockfd, buf, MAXDATASIZE,0)) == -1)
45 {
46 printf("recv() error\n");
47 exit(1);
48 }
49 buf[num - 1]='\0';
50 printf("Server Message: %s\n",buf);
51 }
52
53 close(sockfd);
54
55 return 0;
56 }

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <netdb.h>
9
10 #define PORT 1234
11 #define MAXDATASIZE 1000
12
13 int main(int argc, char *argv[])
14 {
15 int sockfd, num;
16 char buf[MAXDATASIZE + 1] = {0};
17 struct sockaddr_in server;
18
19 if (argc != 2)
20 {
21 printf("Usage:%s <IP Address>\n", argv[0]);
22 exit(1);
23 }
24
25 if ((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1)
26 {
27 printf("socket()error\n");
28 exit(1);
29 }
30 bzero(&server, sizeof(server));
31 server.sin_family = AF_INET;
32 server.sin_port = htons(PORT);
33 server.sin_addr.s_addr = inet_addr(argv[1]);
34 if (connect(sockfd, (struct sockaddr *)&server, \
35 sizeof(server)) == -1)
36 {
37 printf("connect()error\n");
38 exit(1);
39 }
40
41 while (1)
42 {
43 memset(buf, 0, sizeof(buf));
44 if ((num = recv(sockfd, buf, MAXDATASIZE,0)) == -1)
45 {
46 printf("recv() error\n");
47 exit(1);
48 }
49 buf[num - 1]='\0';
50 printf("Server Message: %s\n",buf);
51 }
52
53 close(sockfd);
54
55 return 0;
56 }

服务器程序为:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <signal.h>
10
11 #define PORT 1234
12 #define BACKLOG 5
13 #define MAXDATASIZE 1000
14
15 int main()
16 {
17 int listenfd, connectfd;
18 struct sockaddr_in server;
19 struct sockaddr_in client;
20 socklen_t addrlen;
21 char szbuf[MAXDATASIZE] = {0};
22 int iCount = 0;
23
24 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
25 {
26 perror("Creating socket failed.");
27 exit(1);
28 }
29
30 int opt = SO_REUSEADDR;
31 // setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
32
33 bzero(&server, sizeof(server));
34 server.sin_family = AF_INET;
35 server.sin_port = htons(PORT);
36 server.sin_addr.s_addr = htonl(INADDR_ANY);
37 if (bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1)
38 {
39 perror("Bind()error.");
40 exit(1);
41 }
42 if (listen(listenfd, BACKLOG) == -1)
43 {
44 perror("listen()error\n");
45 exit(1);
46 }
47
48 addrlen = sizeof(client);
49 if ((connectfd = accept(listenfd, (struct sockaddr*)&client, &addrlen)) == -1)
50 {
51 perror("accept()error\n");
52 exit(1);
53 }
54 printf("You got a connection from cient's ip is %s, prot is %d\n", inet_ntoa(client.sin_addr), htons(client.sin_port));
55
56 memset(szbuf, 'a', sizeof(szbuf));
57 while (iCount < 100)
58 {
59 send(connectfd, szbuf, sizeof(szbuf), 0);
60 iCount++;
61 }
62
63 printf("send over!\n");
64 sleep(10);
65
66 close(connectfd);
67 close(listenfd);
68
69 return 0;
70 }

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <signal.h>
10
11 #define PORT 1234
12 #define BACKLOG 5
13 #define MAXDATASIZE 1000
14
15 int main()
16 {
17 int listenfd, connectfd;
18 struct sockaddr_in server;
19 struct sockaddr_in client;
20 socklen_t addrlen;
21 char szbuf[MAXDATASIZE] = {0};
22 int iCount = 0;
23
24 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
25 {
26 perror("Creating socket failed.");
27 exit(1);
28 }
29
30 int opt = SO_REUSEADDR;
31 // setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
32
33 bzero(&server, sizeof(server));
34 server.sin_family = AF_INET;
35 server.sin_port = htons(PORT);
36 server.sin_addr.s_addr = htonl(INADDR_ANY);
37 if (bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1)
38 {
39 perror("Bind()error.");
40 exit(1);
41 }
42 if (listen(listenfd, BACKLOG) == -1)
43 {
44 perror("listen()error\n");
45 exit(1);
46 }
47
48 addrlen = sizeof(client);
49 if ((connectfd = accept(listenfd, (struct sockaddr*)&client, &addrlen)) == -1)
50 {
51 perror("accept()error\n");
52 exit(1);
53 }
54 printf("You got a connection from cient's ip is %s, prot is %d\n", inet_ntoa(client.sin_addr), htons(client.sin_port));
55
56 memset(szbuf, 'a', sizeof(szbuf));
57 while (iCount < 100)
58 {
59 send(connectfd, szbuf, sizeof(szbuf), 0);
60 iCount++;
61 }
62
63 printf("send over!\n");
64 sleep(10);
65
66 close(connectfd);
67 close(listenfd);
68
69 return 0;
70 }

客户端和服务器在两台电脑上运行,电脑通过交换机相连,当服务器将数据发送完成之后,sleep一段时间再关闭链接。根据程序,sleep的时候,手动断电关闭交换机,sleep完成,服务器关闭链路,进程退出。然后再重启服务器,服务器就起不来了,打印:
使用netstat –an查看端口使用情况:
1234端口处于FIN_WAIT2状态,端口处于占用状态,所以bind返回失败了。解决办法:
代码中增加下面语句即可
int opt = SO_REUSEADDR;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
上述语句在TCP服务器代码中是必不可少的。
SOCKET网络编程细节问题1的更多相关文章
- SOCKET网络编程细节问题(4)
SOCKET网络编程快速上手(二)——细节问题(4) 5.慢系统调用及EINTR 还记得前面readn和writen函数么?里面有个EINTR,现在就来谈谈这个,这个很重要. Linux世界有个叫信号 ...
- SOCKET网络编程细节问题3
SOCKET网络编程快速上手(二)——细节问题(3) 3.SIGPIPE问题 人怕牺牲,我们写的程序也一样,人有死不瞑目,程序又何尝不是?程序跑着跑着,突然就崩掉了.好一点的牺牲前告诉你些打印,差点的 ...
- SOCKET网络编程细节问题(2)
SOCKET网络编程快速上手(二)——细节问题(2) 2.TCP数据包接收问题 对初学者来说,很多都会认为:客户端与服务器最终的打印数据接收或者发送条数都该是一致的,1000条发送打印,1000条接收 ...
- SOCKET网络编程5
SOCKET网络编程快速上手(二)——细节问题(5)(完结篇) 6.Connect的使用方式 前面提到,connect发生EINTR错误时,是不能重新启动的.那怎么办呢,是关闭套接字还是直接退出进程呢 ...
- Py西游攻关之Socket网络编程
新闻 管理 Py西游攻关之Socket网络编程 知识预览 计算机网络 回到顶部 网络通信要素: A:IP地址 (1) 用来标识网络上一台独立的主机 (2) IP地址 = 网络地址 + 主机 ...
- Python面向对象进阶和socket网络编程-day08
写在前面 上课第八天,打卡: 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __i ...
- Python面向对象进阶和socket网络编程
写在前面 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __init__(self ...
- Linux Socket 网络编程
Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...
- Python Socket 网络编程
Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...
随机推荐
- C#按LastID进行分页——与lambda形成链式
public static class PageHelper { /// <summary> /// 按页码分页 /// </summary> /// <param na ...
- mysql_oracle_随机查询几条记录
数据库的随机查询SQL 1. Oracle,随机查询20条 select * from ( select * from 表名 order by dbms_random.value ) where ...
- Oracle免费的便捷Web应用开发框架
Oracle免费的便捷Web应用开发框架 APEX 总体来说,APEX是我见过最便捷最高效的开发框架,用起来比PHP还舒服.上手简单,学习成本极低,曾经有个做行政的小女生,在我指导下两天就可以开发出简 ...
- Java高效编程(2) -- Creating and Destroying Objects
Item 1: Consider static factory methods instead of constructors Advantage: One advantage of static f ...
- Android Wear 开发入门——怎样创建一个手机与可穿戴设备关联的通知(Notification)
创建通知 为了创建在手机与可穿戴设备中都能展现的通知,能够使用 NotificationCompat.Builder.通过该类创建的通知,系统会处理该通知是否展如今手机或者穿戴设备中. 导入必要的类库 ...
- HDU Billboard
题目分析:给你n张海报,一个宣传板.让你在满足海报能够贴在最高位置的时候则贴的最高,无法满足时贴的最靠左,输出海报所贴的高度.假设不能贴则输出-1. 一道非常easy,可是我没想出的基础线段树. 算法 ...
- 进程切换switch_to宏第三个参数分析
进程切换一般都涉及三个进程,如进程a切换成进程b,b开始执行,但是当a恢复执行的时候往往是通过一个进程c,而不是进程b. 注意switch_to的调用: switch_to(prev,next,pre ...
- springmvc继承activemq(原创)
1.加入jar包 我项目是用maven构建的,所以这里就给大家贴一下配置了,具体jar大家可以参看下Activemq分类中的文章 <project xmlns="http://mave ...
- 安卓MonkeyRunner源码分析之启动
在工作中因为要追求完成目标的效率,所以更多是强调实战,注重招式,关注怎么去用各种框架来实现目的.但是如果一味只是注重招式,缺少对原理这个内功的了解,相信自己很难对各种框架有更深入的理解. 从几个月前开 ...
- MySQL之 ALTER vs CHANGE vs MODIFY COLUMN
1.ALTER COLUMN 用于设置或者移除某一列的默认(缺省)值, 1.1用法 ALTER TABLE MyTable ALTER COLUMN foo SET DEFAULT 'bar'; AL ...