一、一个简单的服务器和客户对接之后发送“hello world”的程序。
服务器程序:
客户程序:
编译过程中出现的问题以及原因:
1.服务器的 printf ("连接成功!!")无法输出
原因:在linux系统下,printf函数是行缓冲式的输出,当printf遇到\n时,或者缓冲区满时,才会将缓冲区里的内容刷新到标准输出(stdout).因此, printf("连接成功!!"); 等语句的显示不能立刻显示在屏幕上,但是printf("连接成功!!\n"); 可以
2.客户中的struct sockaddr_in对应的地址是哪个?
是服务器的地址描述符(servaddr)
3.bzero后面的参数写什么?
都是对于servaddr的处理
4.最大监听数要自己定义?
对于undp上的代码,最大监听数包含在头文件#include “und.p”,但是在我们自己写的代码要交代清楚
5. if((cliefd=accept(sockfd,(struct sockaddr*)NULL,NULL))!=-1)
accept后面的参数是指客户的一些消息,如果不要就直接写NULL。
6.关于send()和recv()
send(SOCKET s,const char FAR*buf,int len,int flags)
我的理解:把buf中的内容以len的长度(以flags的形式)复制到s的内容中(发送到协议中)
s:一个用于标识已连接套接字的描述字
buf:包含待发送数据的缓冲区
len:缓冲区数据的长度
flags:调用执行方式
send()是一个计算机函数,功能是向一个已经连接的socket发送数据,如果无错误,返回值为所发送数据的总数,否则返回SOCKET_ERROR
recv(SOCKET s,char *buf,int len,int flags)
我的理解:把s的内容以len长度(以flags的形式)复制到数组buf中(从协议中接收)
s:一个用于标识已连接套接字的描述字
buf:存放从缓冲区读取的内容
len:缓冲区的长度
flags:指定调用的方法
recv()先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR;
注意:recv函数仅仅是copy数据,真正的接收数据是协议来完成的。recv函数返回其实际copy的字节数
7.服务器中要写上close(sockfd);语句
因为写上close,在调用完之后就会关闭相关联系
8.inet_pton
这是一个ip地址转换函数,在点分十进制和二进制整数之间的转换,可以处理IPv4和IPv6
点分十进制是IPv4地址标识方法。IPv4中用四个字节表示一个ip地址,每个字节按照十进制表示0~255。点分十进制就是用4个从0~255的数字,来表示一个ip地址。
函数原型:
int inet_pton(int af,const char *src,void *dst);
这个函数转换字符串到网络地址,第一个参数af是地址族,第二个参数*src是来源地址,第三个参数*dat接收转换后的数据
9.程序中可能会运行不了,是因为会遇到不同的端口号,把端口号改成合适的就可以运行了
二、一个从服务器获得要的图片/文件的程序
服务器程序:
客户程序:
编译过程中出现的问题以及原因:
1.完成该过程的思路是什么?
当连接阶段完成之后,我们就可以互相传输文件。文件包括文件名和文件内容,这两个变量我们都要交代清楚。文件传输大致是这样的:现在两边都声明文件名和存放文件的缓存区名,然后把相应的存储空间清零。我们在客户端写入我们想要的文件名,名字放在缓存区中,发送给服务器。服务器从缓冲区中接收到信息,通过recv复制到服务器中,服务器通过fopen以二进制的形式查找到相应的内容,把内容通过send放在缓冲区中。客户端从缓冲区中读取到内容,通过recv复制到我们声明好的文件变量对应的文件,然后用fwrite打开并写入其中。
特别有一点要注意的,recv()和send()这两个函数可以理解为连接服务器、客户端以及缓冲区,它们的功能和copy差不多,实际上数据的复制是在协议中进行的。
2.函数strncpy(char *dest, const char *src, int n)
strncpy是c语言复制字符的函数。把src的前n个字符复制到dest中
3.fopen()、fwrite()、fread()
函数原型:fopen(const char * path,const char * mode)
进一步理解:fopen(文件名,使用文件方式)
fopen是用来实现文件打开的函数
使用文件的方式
r 只读 w 只写 rb 为了输入数据,打开一个二进制文件 wb 为了输出数据,打开一个二进制文件
用二进制的方式向文件读一组数据
fread(buffer,size,count,fp);
从文件中读一个数据块
buffer:用来存放从文件读入的数据的存储区的地址
size:要读的字节的大小
count:要读多少个数据项(每个数据项长度为size)
fp:FILE类型指针
用二进制的方式向文件写一组数据
fwrite(buffer,size,sount,fp);
向文件写一个数据块
buffer:把此地址开始的存储区中的数据向文件输出
size:要写的字节的大小
count:要写多少个数据项(每个数据项长度为size)
fp:FILE类型指针
4.ping
ping是window、linux中一个命令。
ping也属于一个通信协议,是TCP/IP协议的一部分
利用ping命令可以检查网络是否连通,可以很好地帮助我们分析和判定网络故障
应用格式:Ping空格 IP地址。
三、一个服务器和客户端通信的程序
服务器程序:
客户端程序:
编译过程中出现的问题以及原因:
1.server完成一次对接之后(在server结束),再次执行程序,出现address already in use这样的错误信息,表示我端口已经被占用
(参考资料https://www.cnblogs.com/CodeMIRACLE/p/5122063.html)
只要在bind函数之前加入下面代码即可:
bind普遍遭遇的问题是试图绑定一个已经在使用的端口,该陷阱是也许没有活动的套接字存在,但仍然禁止绑定端口,它是由TCP套接字状态TIME_WAIT引起的。在TIME_WAIT状态退出之后,套接字被删除,该地址才能被重新绑定而不出问题。
2.怎么查看程序运行失败是出现什么问题?
因为我们在头文件里有交代#include<errno.h>,所以我们是可以通过调用strerror(errno)来查看到底是什么错误
strerror
头文件:#include<string.h>
作用:通过标准错误的标号,获得错误的描述字符串 ,将单纯的错误标号转为字符串描述,方便用户查找错误
参数:错误标号(errno)
errno
是记录系统的最后一次错误代码,代码是一个int型的值,每一个值表示着不同的含义,可以通过查看该值推测出错的原因
3.通配符地址(INADDR_ANY)
INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或"所有地址"、"任意地址"。 一般来说,在各个系统中均定义成为0值