一、问题思考
问1.网络通信应用在什么场合?通信的前提是什么?
答1.主要应用在不同主机进程间的互相通信,同一主机的进程也可以使用网络进行通信。通信的前提是如何标识通信进程的唯一,由于不同主机的进程极有可能具有相同的PID,因此,在网络中单单靠PID是无法准确进行标识进程身份的,TCP/IP协议族网络层的IP地址可以唯一的标识连入网络的主机。
问2.socket编程重点是什么?
答2.掌握基于TCP、UDP的S/C架构的编程要点;掌握网络通信方式之间的区别和应用场合。
问3.什么是网络模型?
答3.网络模型主要分为4层,从上至下依次为:应用层、运输层、协议层、链路层。如图所示。
问4.什么是socket套接字?
答4.是一种文件描述符。有三种类型:
①流式套接字(SOCK_STREAM)——过程类似于打电话。提供可靠的、面向连接的通信流,对应使用TCP/IP协议,能够保证数据传输的正确性和顺序性。
②数据报套接字(SOCK_DGRAM)——过程类似于手机之间发短信。无连接服务、数据的传输是独立的不需要经过对方的响应,可靠性无保证。对应使用UDP/IP协议。
③原始套接字(SOCK_RAW)——该套接字直接基于IP地址。
二、TCP、UDP通信编程模型
主要相关操作函数
1. 创建套接字
#include<sys/types.h> #include<sys/socket.h> int socket(int protofamil,int type,int protocol);
protofamil 设置协议族即设置socket的地址类型,定义在/usr/include/bits/socket.h 内,有:AF_INET(IPV4——32位IP、16位的端口号)、AF_INET6(IPV6)、AF_LOCAL(Unix域socket)、AF_ROUTE等等; type 常用的有SOCK_STREAM、SOCK_DGRAM和SOCK_RAW; protocol 用来指定socket所使用的传输协议编号,通常此参考不用管它,设为0即可。
返回值:成功——socket描述符;失败——(-1)
2.绑定地址
#include<sys/types.h> #include<sys/socket.h> int bind(int sockfd,struct sockaddr * my_addr,int addrlen);
sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。 my_addr:指向sockfd要绑定的协议地址。IPv4对应的协议地址结构为: struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ }; /* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ }; addrlen:对应的是地址的长度,使用sizeof来计算。
返回值:成功——(0),失败——(-1)
3.监听
#include<sys/socket.h> int listen(int sockfd,int backlog);
参数backlog是能处理的最大连接数目,如果连接数目达此上限则client端将出错。
返回值:成功——(0),失败——(-1)
4.建立连接
#include<sys/types.h> #include<sys/socket.h> int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);
参数:sockaddr 服务器的socket地址,addrlen为socket地址的长度。
返回值:成功——(0),失败——(-1)
5.接受请求
#include<sys/types.h> #include<sys/socket.h> int accept(int sockfd,struct sockaddr * addr,int * addrlen);
参数:sockfd ——用来监听客户的一个端口号;addr——客户机的地址数据;addrlen即前面这个地址数据的大小
返回值:成功——已建立连接的新的套接字描述符,可用于read/write函数;失败——(-1)
6.读写操作
第①组:用于面向连接的TCP编程中
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count);
返回值:成功——字节数;失败——(-1)
第②组:用于面向连接的TCP编程中
#include<sys/types.h> #include<sys/socket.h> int recv(int sockfd,void *buf,int len,unsigned int flags); int send(int sockfd,const void * msg,int len,unsigned int falgs);
参数:buf/msg分别指向接收缓冲区和发送的信息,len是接收或发送的最大长度,flags通常设置为0。
返回值:成功——字节数;失败——(-1)
第③组:可用于面向连接和无连接的套接字
#include<sys/types.h> #include<sys/socket.h> int recvfrom(int sockfd,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen); int sendto ( int sockfd, const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen ) ; int recvmsg(int sockfd,struct msghdr *msg,unsigned int flags); int sendmsg(int sockfd,const strcut msghdr *msg,unsigned int flags);
返回值:成功——字节数;失败——(-1)
7.关闭操作
#include<unistd.h> int close(int fd);
8.其他:申请共享内存
#include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg); 函数功能:得到一个共享内存标识符 参数含义: key:常设置为IPC_PRIVATE(0),建立新共享内存对象,大于0的32位整数:视参数shmflg来确定操作。 size:新建的共享内存大小,以字节为单位 shmflg:根据如下进行设置 0:取共享内存标识符,若不存在则函数会报错; IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符; IPC_CREAT|IPC_EXCL:如果内核中不存在键值 与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错; 共享内存的存取权限:S_IRUSR|S_IWUSR...
#include <sys/types.h> #include <sys/shm.h> void *shmat(int shmid, const void *shmaddr, int shmflg); 函数功能:映射共享内存区到调用该函数的进程地址空间 参数含义: shmid:共享内存标识符,由shmget函数产生 shmaddr:通常指定为NULL(0)让内核自己决定一个合适的地址位置 shmflg:如果设置为SHM_RDONLY-只读模式,其他值为读写模式 成功:返回共享内存地址
#include <sys/types.h> #include <sys/shm.h> int shmdt(const void *shmaddr); 函数功能:断开共享内存连接 参数分析: shmaddr:要断开共享内存的起始地址
三、socket编程框架与示例
1.TCP网络编程设计:TCP并发服务器设计——每一个客户机的请求由服务器创建的一个子进程/线程来处理,不是用服务器进程来处理(TCP循环服务器:一次只能处理一个客户机额请求)。优点:可以“同时”响应多个客户端的服务请求。
代码功能实现:客户端A和B通过服务端进行通信
1 //编译指令:gcc -o server server.c 2 //执行指令:./server 3 #include<stdio.h> 4 #include<stdlib.h> 5 #include<sys/types.h> //数据类型定义 6 #include<sys/stat.h> 7 #include<netinet/in.h> //定义数据结构sockaddr_in 8 #include<sys/socket.h> //提供socket函数及数据结构 9 #include<string.h> 10 #include<unistd.h> 11 #include<signal.h> 12 #include<sys/ipc.h> 13 #include<errno.h> 14 #include<sys/shm.h> 15 #include<time.h> 16 #define PERM S_IRUSR|S_IWUSR 17 #define MYPORT 5000 //宏定义定义通信端口 18 #define MAX_CLIENT 5 //宏定义,定义服务程序可以连接的最大客户数量 19 #define WELCOME "chating room:" //宏定义,当客户端连接服务端时,想客户发送此欢迎字符串 20 21 //转换函数,将int类型转换成char *类型 22 static void itoa(int i,char*string) 23 { 24 int power,j; 25 j=i; 26 for(power=1;j>=10;j/=10) 27 power*=10; 28 for(;power>0;power/=10) 29 { 30 *string++='0'+i/power; 31 i%=power; 32 } 33 *string='