++找出全书你认为最重要的一章,深入重新学习一下++
随着学习的深入,多门课程涉及到网络编程的实现,网络编程涉及范围广,一组网络编程的程序可以涵盖诸多知识点,故而我认为这一章的内容有助于多门课的理解与学习,是最重要的一章。
教材学习内容总结
知识点
- 客户端-服务器编程模型
- 网络
一个网络主机的硬件组成
以太网段
桥接以太网
一个因特网应用程序的硬件和软件组织
- IP
网络之间互连的协议也就是为计算机网络相互连接进行通信而设计的协议。在因特网中,它是能使连接到网上的所有计算机网络实现相互通信的一套规则,规定了计算机在因特网上进行通信时应当遵守的规则。任何厂家生产的计算机系统,只要遵守IP协议就可以与因特网互连互通。IP地址具有唯一性,根据用户性质的不同,可以分为5类。另外,IP还有进入防护,知识产权,指针寄存器等含义。
结合知识点进行编程准备
++服务器与客户端流程图++
++详细理解++
服务器的处理:
(1)使用socket系统调用,生成一个TCP协议模块与应用程序之间进行通信的套接字;使用bind系统调用指定端口号;
(2)使用bind系统调用指定端口号;
(3)使用listen系统调用,指定连接接收队列的长度,并等待来自客户端的连接请求。
前三步完成了启动服务器程序的工作。一旦listen监听到有客户端的连接,就调用accept接收连接。
希望与服务器通信的进程称为客户,客户所运行的计算机环境称为客户端,有时两个概念混用。
客户端的处理:
(1)使用socket系统调用,打开TCP协议模块与应用程序之间的通信线路;
(2)使用connect系统调用,指定IP地址和端口号,和服务器相应的服务应用程序建立TCP协议的连接请求;
客户端和服务器程序在建立连接后,使用send和recv调用完成数据的发送和接收工作。等待数据传送结束后,各自调用close关闭套接字。
使用TCP协议的Socket通信程序包括服务程序和客户程序。
需要特别注意的类型
sockadd和sockaddr_in结构:
① sockaddr 结构
struct sockaddr
{
unsigned short sa_family; /*地址族,AF_xxx有IPV4与IPV6等*/
char sa_data[14]; /*14字节的协议地址*/
};
sa_family一般为AF_INET,表示Internet协议族,如是AF_UNIX表示UNIX协议簇;sa_data中包含该socket的IP地址和端口号。
② in_add结构,用来存储四字节的IP地址
struct in_addr{
unsigned long s_addr;
};
③ sockaddr_in结构
struct sockaddr_in
{
short int sin_family; /*地址族*/
unsigned short int sin_port; /*端口号*/
struct in_add sin_addr; /*IP地址*/
unsigned char sin_zero[8]; /*填充0以保持与struct sockaddr同样大小*/
};
该结构中sin_zero使得sockaddr和sockaddr_in指针类型相互转换;sin_port和sin_addr必须是网络字节顺序,因为它们被封装在包的IP和UDP层,而sin_family不发送到网络上可以是本机字节顺序。
相关函数
++1.socket()函数++
该函数用于根据指定的地址族、数据类型和协议来分配一个套接字的描述字及其所用的资源。Socket函数原型为:
int socket( int domain , int type , int protocol ) ;
参数说明:
a、 参数domain指定地址描述,一般为AP_INET;
b、 参数type指定socket类型:SOCK_STREAM和SOCK_DGRAM;
c、参数protocol通常为0;
d、 函数返回值为一个整型socket描述符,在bind函数中调用。
++2.bind()函数++
该函数用于将一个本地地址与一个套接字绑定在一起。
int bind( int sockfd , struct sockadd* my_addr , int addrlen) ;
a、sockfd:socket描述符,使用socket函数返回值,将该socket与本机上的一个端口相关联。
在设计服务器端程序是需要调用bind函数,以在该端口上监听服务请求;而客户端一般不需要调用bind函数,因为只需知道服务器IP地址,并不关心客户通过哪个端口与服务器建立连接,内核会自动选择一个未被占用的端口供客户端来使用。
b、my_addr:指向包含本机IP地址及端口号等信息的sockaddr类型的指针。
c、addrlen:sizeof( struct sockaddr)的值。
d、bind函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码。
++3.connect()函数++
与远程服务器建立一个TCP连接。
int connect(int sockfd, struct sockaddr* serv_addr, int addrlen);
a、sockfd:目的服务器的socket描述符。
b、serv_addr:指向包含目的服务器的IP地址及端口号的指针。
c、addrlen:sizeof( struct sockaddr)的值。
d、connect函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,进行服务器端程序设计时不需调用connect函数。
++4.listen()函数++
在服务器端程序中,当socket与某一端口绑定后,需要监听该端口,及时处理到达该端口上的服务请求。
int listen(int sockfd, int backlog);
a、sockfd:Socket系统调用返回的socket描述符。
b、backlog:指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待接收backlog限制了队列中等待服务的请求数目,系统缺省值为20。
c、listen函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码。
++5.accept()函数++
当某个客户端试图与服务器监听的端口连接时,该连接请求将排队等待服务器用accept接收它并为其建立一个连接。
int accept(int sockfd, struct sockaddr* addr, int* addrlen);
a、sockfd:被监听的socket描述符。
b、addr:sockaddr类型的指针变量,用来存放提出连接请求服务的主机信息。
c、accept函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,如果没有错误,accept()函数返回一个新想socket描述符,供这个新连接来实用,而服务器可以继续在以前的socket上监听,同时可以在新的socket描述符上进行数据发送和数据接收(sent()和recv()操作)。
++6.sent()和recv()函数++
用于在面向连接(TCP)的socket上进行数据传输。
send()函数原型:
int send(int sockfd, const void* msg, int len, int flags) ;
a、sockfd:用于传输数据的socket描述符。
b、msg:是一个指向要发送数据的指针。
c、len:以字节为单位的数据的长度。
d、flags:一般情况下置为0。
e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,否则返回所发送数据的总数,该数字可能小于len中所规定的大小。
recv()函数原型:
int recv(int sockfd, void* buf, int len, unsigned int flags);
a、sockfd:是接收数据的socket描述符。
b、buf:是存放接收数据的缓冲区。
c、len:以字节为单位的缓冲区的长度。
d、flags:一般情况下置为0。
e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,无错则返回读入的字节数,如果连接被中止,返回0。
++7.endto()和recvfrom()函数++
这两个函数是利用数据报方式(UDP)进行数据传输。在无连接的数据报socket方式下,由于本地socket并没有与远程机器建立连接,所以在发送数据时应指明目的地址。
sendto()原型:
int sendto(int sockfd, const void* msg, int len, unsigned int flags, const struct sockaddr* to, int tolen);
a、sockfd:用于传输数据的socket描述符。
b、msg:是一个指向要发送数据的指针。
c、len:以字节为单位的数据的长度。
d、flags:一般情况下置为0。
e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,否则返回所发送数据的总数,该数字可能小于len中所规定的大小。
f、表示目的机器的IP地址和端口号。
g、tolen:被赋值为sizeof(struct sockaddr)。
recvfrom函数原型:
int recv(int sockfd, void* buf, int len, unsigned int flags, struct sockaddr* from, int fromlen);
a、sockfd:是接收数据的socket描述符。
b、buf:是存放接收数据的缓冲区。
c、len:以字节为单位的缓冲区的长度。
d、flags:一般情况下置为0。
e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,无错则返回读入的字节数,如果连接被中止,返回0。
f、from:保存源机器的IP地址和端口号。
g、fromlen:常被赋值为sizeof(struct sockaddr)。
当对于数据报socket调用了connect()函数时,也可以用send()和recv()进行数据传输,但该socket仍然是数据报socket,并利用传输层的UDP服务。但是在发送或接收数据报时,内核会自动为它加上目的地址和源地址信息。
++8.close()和shutdown()函数++
当所有的数据操作结束后,可以调用close函数来释放该socket资源,从而停止在该socket上的任何数据操作。
也可以调用shutdown函数,允许只停止在某个方向上的数据传输,而另一个方向上的数据传输继续进行。例如可以关闭某一个socket上的写操作uo允许继续在该socket上接收数据,直到读入所有数据。
但是,shutdown函数并不关闭套接字所占用的所有资源,除非调用close函数来释放。
看看两个函数原型:
close(int sockfd);
shutdown(int sockfd, int how);
how参数的值和含义:
0:不允许继续接收数据;
1:不允许继续发送数据;
2:不允许继续发送和接收数据。
shutdown在操作成功时返回0,错误时返回-1,并置errno值。
++9.字节顺序转换函数++
htons():Host to Network Short的缩写,该函数将主机的无符合短整型数字节顺序转换成网络字节顺序。
htonl():Host to Network Long的缩写,该函数将主机的无符合长整型数字节顺序转换成网络字节顺序。
ntohs():Network to Host Short的缩写,该函数将无符号短整型数从网络字节顺序转换为主机字节顺序。
ntohl():Network to Host long的缩写,该函数将无符号长整型数从网络字节顺序转换为主机字节顺序。
程序准备
codeblocks设置:在进行客户端-服务器编程的时候,要想运行,则需要进行一定的设置
链接库:menu-->Projrcy-->build options-->Debug->Linker Setting-->Other Linker Options: 加上 “-lws2_32“
设置环境:Settings->Environment…->取消勾选第二、三项(Allow onlyone running instance(will take place after restart);Use an already running instance(if possible))->重启codeblocks
注意:双击图标运行一个c程序,想要运行几个c程序就双击图标几回。
两个系统的服务器-客户端程序示例
WINDOWS(一组尬聊程序)
服务器
#include <stdio.h>
#include <stdlib.h>
#include <Winsock2.h>
#include <string.h>
#define MY_PORT 3434
int main()
{
SOCKET listen_sock,new_sock;
struct sockaddr_in my_addr;
int dummy;
int bytes_recvd;
int flag = 1;
char *buffer="你好啊,我是服务器小天使";
char buffer_Client[100];;
char Bye_Client[] = "over";
char buffer_Server[100];
WSADATA wsaData;
WSAStartup(MAKEWORD(1,1),&wsaData);
listen_sock = socket(AF_INET,SOCK_STREAM,0);
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MY_PORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bind(listen_sock,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));
listen(listen_sock,5);
new_sock = accept(listen_sock,NULL,&dummy);
send(new_sock,buffer,strlen(buffer),0);
while(1){
memset(buffer_Client, 0, sizeof(buffer_Client));
bytes_recvd = recv(new_sock, buffer_Client, sizeof(buffer_Client), 0);
printf("客户端: %s
",buffer_Client);
if(strcmp(buffer_Client,Bye_Client)==0)
{
printf("客户端要去洗澡了
");
send(new_sock,Bye_Client,strlen(Bye_Client),0);
flag = 0;
break;
}
printf("服务器:");
memset(buffer_Server, 0, sizeof(buffer_Server));
gets(buffer_Server);
send(new_sock, buffer_Server, strlen(buffer_Server), 0);
}
closesocket(new_sock);
closesocket(listen_sock);
WSACleanup();
return 0;
}
客户端
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <Winsock2.h>
#include <string.h>
#define MY_PORT 3434
int main()
{
SOCKET conn_sock;
struct sockaddr_in remote_addr;
int bytes_recvd;
int flag = 1;
int i;
char buffer_Client[100] = "hhhhhh傻了吧";
char buffer_Server[100];
WSADATA wsaData;
WSAStartup(MAKEWORD(1,1),&wsaData);
conn_sock = socket(AF_INET,SOCK_STREAM,0);
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(MY_PORT);
remote_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
connect(conn_sock,(struct sockaddr*)&remote_addr,sizeof(struct sockaddr));
while(flag)
{
memset(buffer_Server, 0, sizeof(buffer_Server));
bytes_recvd = recv(conn_sock, buffer_Server, sizeof(buffer_Server), 0);
printf("服务器: %s
",buffer_Server);
if(strcmp(buffer_Server,"over")==0)
{
printf("服务器乖乖下线了
");
flag = 0;
break;
}
printf("客户端:");
memset(buffer_Client, 0, sizeof(buffer_Client));
gets(buffer_Client);
send(conn_sock, buffer_Client, strlen(buffer_Client), 0);
}
closesocket(conn_sock);
WSACleanup();
return 0;
}
LINUX(传文件与统计字数)
服务器
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#define MYPORT 155325
#define QUEUE 20
#define BUFFER_SIZE 404800
void Receive(int conn,char buffer[]);
int MyWc(char buffer[],int length);
int main()
{
///定义sockfd
int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);
///定义sockaddr_in
struct sockaddr_in server_sockaddr;
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(MYPORT);
server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
///bind,成功返回0,出错返回-1
if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)
{
perror("bind");
exit(1);
}
///listen,成功返回0,出错返回-1
if(listen(server_sockfd,QUEUE) == -1)
{
perror("listen");
exit(1);
}
///客户端套接字
char buffer[BUFFER_SIZE];
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
///成功返回非负描述字,出错返回-1
int conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);
if(conn<0)
{
perror("connect");
exit(1);
}
memset(buffer,0,sizeof(buffer));
int len = recv(conn, buffer, sizeof(buffer),0);
if(strcmp(buffer,"FILE
")==0)
{
printf("即将收到文件:。。。
");
Receive(conn,buffer);
}
close(conn);
close(server_sockfd);
return 0;
}
void Receive(int conn,char buffer[])
{
int length2 = 0;
int write_length;
int sum = 0;
bzero(buffer, sizeof(buffer));
FILE *fp = fopen("b.txt", "w");
char FileName[15];
memset(buffer,0,sizeof(FileName));
recv(conn,FileName,15, 0);
if (fp == NULL)
{
printf("服务器文件无法被创建
");
exit(1);
}
while(length2 = recv(conn, buffer,BUFFER_SIZE, 0))
{
if (length2 < 0)
{
printf("接受文件 %s 失败
",FileName);
break;
}
write_length = fwrite(buffer, sizeof(char), length2, fp);
// printf("length2 = %d,write_length = %d
",length2,write_length);
if (write_length < length2)
{
printf("服务器文件写入失败
");
break;
}
// printf("
********************************************************
");
sum = sum + MyWc(buffer,write_length);
// printf("
sum = %d
",sum);
bzero(buffer, BUFFER_SIZE);
length2 = 0;
}
fclose(fp);
printf("sum = %d",sum);
printf(" %s 成功接收
",FileName);
}
int MyWc(char buffer[],int length)
{
int i,j;
int num=0;
// printf("%s",buffer);
if( ((buffer[0]>='A')&&(buffer[0]<='Z')) || ((buffer[0]>='a')&&(buffer[0]<='z')) )num++;
for(i=1;i<length;)
{
if( (buffer[i] == ' ')||(buffer[i]=='
') ||(buffer[i]=='
') ||(buffer[i]==' ') ||(buffer[i]=='.')||(buffer[i]=='?') ||(buffer[i]=='!') ||(buffer[i]==':')||(buffer[i]==',') ||(buffer[i]=='@') ||(buffer[i]=='&')||(buffer[i]=='*') ||(buffer[i]=='~')||(buffer[i]=='^') ||(buffer[i]==';') ||(buffer[i]==')') ||(buffer[i]=='(') ||(buffer[i]=='"') )
{
for(j = i+1;j<length;j++)
{
if( ((buffer[j]>='A')&&(buffer[j]<='Z')) || ((buffer[j]>='a')&&(buffer[j]<='z')) )
{
// printf("(%d,%c),(%d %c)
",i,buffer[i],j,buffer[j]);
num++;
i = j+1;
break;
}
}
}
i++;
}
return num;
}
客户端
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#define MYPORT 155325
#define BUFFER_SIZE 404800
void Send(int sock_cli);
int main()
{
///定义sockfd
int sock_cli = socket(AF_INET,SOCK_STREAM, 0);
///定义sockaddr_in
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(MYPORT); ///服务器端口
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ///服务器ip
///连接服务器,成功返回0,错误返回-1
if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("connect");
exit(1);
}
char sendbuf[BUFFER_SIZE];
char recvbuf[BUFFER_SIZE];
memset(sendbuf, 0, sizeof(sendbuf));
memset(recvbuf, 0, sizeof(recvbuf));
while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
{
// printf("%s",sendbuf);
send(sock_cli, sendbuf, sizeof(sendbuf),0); ///发送
if(strcmp(sendbuf,"FILE
")==0)
{
printf("呵呵
");
Send(sock_cli);
}
// recv(sock_cli, recvbuf, sizeof(recvbuf),0); ///接收
// fputs(recvbuf, stdout);
break;
memset(sendbuf, 0, sizeof(sendbuf));
memset(recvbuf, 0, sizeof(recvbuf));
}
close(sock_cli);
return 0;
}
void Send(int sock_cli)
{
printf("进入传文件步骤。。。
请输入文件名:");
char FileName[15];
char buffer[BUFFER_SIZE];
int length = 0;
scanf("%s",FileName);
send(sock_cli, FileName, sizeof(FileName),0);
FILE *fp = fopen(FileName,"r");
if (fp == NULL)
{
printf("******%s Not Found!******
",FileName);
}
else
{
bzero(buffer, BUFFER_SIZE);
while( (length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
{
// printf("length = %d
",length);
// 发送buffer中的字符串到new_server_socket,实际上就是发送给客户端
if (send(sock_cli, buffer, length, 0) < 0)
{
printf("%s 传送失败
", FileName);
break;
}
bzero(buffer, BUFFER_SIZE);
}
fclose(fp);
printf("%s 传送成功
", FileName);
close(sock_cli);
}
}
Web服务器
- 每条由Web服务器返回的内容都是和它管理的某个文件相关联的,这些文件中的每一个都有一个唯一的名字URL。
eg。 http://www/google.com:80/index.html
关于URL的解析,除了书上P666页以外,网上也有一些资料,有兴趣可以点开链接看看。
对于TINY Web服务器,其中有几个函数比较重要:doit,clienterror,read_requesthdrs,parse_uri,serve_static,serve_dynamic。
教材学习和代码调试中的问题和解决过程
由于网络编程涉及到的知识点,比如函数、变量、什么协议族之类的,很多很凌乱,我有些傻傻搞不清楚,这是这一章里我最想解决的问题,所以放进了笔记里。
教材习题-(答案在此不赘述,我就记叙做题思路)
11.1:十六进制地址和点分十进制地址转换
做题方法:十六进制两个数字为一组,每一组各转为十进制,以点把每一组分开。
11.2:htonl();inet_pton();字符串输出
11.3:inet_pton();nthol()输出
Linux下inet_pton和inet_ntop这2个IP地址转换函数,可以在将IP地址在“点分十进制”和“二进制整数”之间转换。而且,这2个函数能够处理ipv4和ipv6。
11.4:
getaddrinfo:仅支持IPv4,getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,返回的是一个sockaddr结构的链表而不是一个地址清单。这些sockaddr结构随后可由套接口函数直接使用。如此一来,getaddrinfo函数把协议相关性安全隐藏在这个库函数内部。
getnameinfo:这个函数与getaddrinfo互补,它以一个套接口地址为参数,返回一个描述主机的字符串和一个描述服务的字符串。
代码托管
上周考试错题总结
- 实验5:使用openssl进行混合密码系统加密时,会话秘钥的分发最可能用到()
A .
AES_encrypt
B .
RSA_public_encrypt
C .
AES_decrypt
D .
RSA_private_decrypt
E .
AES_cbc_encrypt
F .
RSA_private_encrypt
G .
RSA_public_decrypt
正确答案: B D
非对称算法的应用:
秘钥分发:用对方公钥加密,对方用自己的私钥解密
签名验签:签名主要是用自己私钥加密,对方用自己公钥验签
- 实验4,Linux中通过把设备抽象成文件来简化操作的,我们可以用open/read/write/close来像访问文件一样访问设备, 这里需要一个结构提供设备驱动程序接口,这个结构是()
A .
struct file
B .
struct inode
C .
struct file_operations
D .
struct UTMP
正确答案: C
在系统内部,I/O设备的存取操作通过特定的入口点来进行,而这组特定的入口点恰恰是由设备驱动程序提供的。通常这组设备驱动程序接口是由结构file_operations结构体向系统说明的,它定义在include/linux/fs.h中
- 实验3中,在Ubuntu虚拟机中编译多线程程序时,gcc使用()选项
A .
-g
B .
-lthread
C .
-pthread
D .
-lpthread
正确答案: C
实际环境中只有-pthread可用
- 实验1中使用mount命令时,会涉及到()的修改。
A .
/etc/fstab
B .
/etc/hosts
C .
/etc/passwd
D .
/etc/exports
正确答案: D
nfs服务器的配置,配置文件/etc/exports:
复制代码
ro 该主机对该共享目录有只读权限
rw 该主机对该共享目录有读写权限
root_squash 客户机用root用户访问该共享文件夹时,将root用户映射成匿名用户
no_root_squash 客户机用root访问该共享文件夹时,不映射root用户
all_squash 客户机上的任何用户访问该共享目录时都映射成匿名用户
anonuid 将客户机上的用户映射成指定的本地用户ID的用户
anongid 将客户机上的用户映射成属于指定的本地用户组ID
sync 资料同步写入到内存与硬盘中
async 资料会先暂存于内存中,而非直接写入硬盘
insecure 允许从这台机器过来的非授权访问
- 实验1中需要交叉编译,因为程序要在ARM实验箱的Linux中执行,交叉编译是在ARM实验箱中完成的,hello程序也是在ARM实验箱中执行的。
A .
正确
B .
错误
正确答案: B
交叉编译在UBuntu虚拟机中完成,执行是在ARM实验箱的Linux中完成
- 实验1:mount -t nfs -o nolock 192.168.0.56:/root/share /host,其中的IP是()的IP
A .
Windows 宿主机
B .
Ubuntu虚拟机
C .
ARM实验箱
D .
以上都不对
正确答案: B
嵌入式开发中,通过nfs系统把Ubuntu虚拟机的一个目录映射成ARM实验箱的Linux系统的一个目录进行调试是一个惯用法,程序调试没有问题了,再烧写到实验箱的Linux的系统中,这样实验箱重启了程序也可以用了。
- 有关套接字接口函数open_clientfd()、open_listenfd(),下面说法正确的是()
A .
这两个函数中open_clientfd()只可以用于客户端编程
B .
这两个函数中open_clientfd()可以用于客户端和服务器端编程
C .
这两个函数中open_listenfd()只可以用于服务器端编程
D .
open_clientfd()中的port参数是客户端的端口
E .
open_clientfd()中的port参数是服务器端的端口
F .
open_clientfd()返回的clientfd可以有Unix I/O接口读写
G .
open_listenfd()返回的listenfd可以有Unix I/O接口读写
正确答案: A C E F
p660
- 有关socket 接口中的connect(),下面说法正确的是()
A .
这个函数用于客户端编程
B .
这个函数用于服务器端编程
C .
调用connect会发生阻塞,连接成功程序会继执行
D .
调用connect()成功返回的文件描述符可以用来数据传输
正确答案: A C D
p654
- 有关socket接口中的socket(),下面说法正确的是()
A .
不论客户端编程还是服务器端编程都要调用socket()
B .
socket()中的type参数设置为SOCK_STREAM时,基于TCP的,数据传输比较有保障
C .
socket()中的type参数设置为SOCK_DGRAM时,基于TCP的,数据传输比较有保障
D .
使用socket()返回的文件描述符通过read(),write()就可以传输数据了
E .
socket()中的protocol参数一般设为0
F .
socket()中的type参数设置为 SOCK_RAW ,允许对底层协议如IP或ICMP进行直接访问
G .
socket()可用getaddrinfo返回的ai_family,ai_socktype和ai_protocol填充
正确答案: A B E F G
p654
结对
- 本周结对学习情况
学习进度条
时间 | 代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 |
---|---|---|---|---|
目标 | 5000行 | 16篇 | 400小时 | |
第1周 | 9/9 | 1/1 | 19/19 | 熟练下载安装技能,锻炼解决问题能力 |
第2周 | 380/389 | 2/3 | 26/45 | 1、7章 |
第3,4周 | 1270/1659 | 3/6 | 42/87 | 2、10章 |
第5周 | 20/1679 | 2/8 | 30/117 | 实验一&3章 |
第6周 | 223/1902 | 1/9 | 20/137 | 课堂测试、课下作业、第八章 |
第7周 | 3020/4770 | 2/11 | 20/157 | 实验二、第四章 |
第8、9周 | 21665/26435 | 3/14 | 55/212 | 实验三、第六章 |
第10、11周 | 410/26845 | 3/17 | 40/252 | 实验四、第九章 |
第12、13周 | 2437/287021 | 2/19 | 38/290 | 实验五、第十二章 |