手机免费建网站软件,中国旺旺(00151) 股吧,网站开发的技术可行性,中国中国建设银行网站首页Linux系统编程—socket网络编程 理论概念1. TCP与UDP对比端口号作用 socket开发过程服务端1. socket 创建套接字2. bind 绑定IP端口3. listen 监听客户端4. accept 接收客户端5. read / write 数据传输 客户端1. socket 创建套接字2. connect 连接服务3. read / write 数据传输… Linux系统编程—socket网络编程 理论概念1. TCP与UDP对比端口号作用 socket开发过程服务端1. socket 创建套接字2. bind 绑定IP端口3. listen 监听客户端4. accept 接收客户端5. read / write 数据传输 客户端1. socket 创建套接字2. connect 连接服务3. read / write 数据传输 server.c与client.c程序案例 理论概念
1. TCP与UDP对比 TCP面向连接如打电话要先拨号建立连接UDP是无连接的即发送数据之前不需 要建立连接 TCP提供可靠的服务。也就是说通过TCP连接传送的数据无差错不丢失不重复且按序到达;UDP尽最大努力交付即不保证可靠交付 TCP面向字节流实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的 UDP没有拥塞控制因此网络出现拥塞不会使源主机的发送速率降低对实时应用很有用如IP电话实时视频会议等 每一条TCP连接只能是点到点的;UDP支持一对一一对多多对一和多对多的交互通信 TCP首部开销20字节;UDP的首部开销小只有8个字节 TCP的逻辑通信信道是全双工的可靠信道UDP则是不可靠信道
端口号作用 一台拥有IP地址的主机可以提供许多服 比如Web服务、FTP服务、SMTP服务等 通过“IP地址端口号”来区 分不同的服务端口提供了一种访问通道服务器一般都是通过端口号来识别的。
socket开发过程 服务端
1. socket 创建套接字
函数原型 #include sys/types.h #include sys/socket.hint socket(int domain, int type, int protocol);返回值 成功返回网络标识符失败返回 -1 参数分析 domain: 指明所使用的协议族通常为AF_INET表示互联网协议族TCP/IP协议族
AF_INET IPv4因特网域AF_INET6 IPv6 因特网域AF_UNIX Unix 域AF_ROUTE 路由套接字AF_KEY 密钥套接字AF_UNSPEC 未指定
type: 指定socket类型
SOCK_STREAM 流式套接字提供可靠的、面向连接的通信流它使用 TCP 协议从而保证了数据传输的正确性和顺序性SOCK_DGRAM 数据报套接字定义了一种无连接的数据数据通过相互独立的报文进行传输是无序的并且不保证是可靠、无差错的。它使用数据报协议UDPSOCK_RAW 允许程序使用低层协议原始套接字允许对底层协议如 IP 或ICMP 进行直接访问功能强大但使用较为不便主要用于一些协议的开发。
protocol: 通常赋值 0
0 选择 type 类型对应的默认协议IPPROTO_TCP TCP 传输协议IPPROTO_UDP UDP 传输协议IPPROTO_SCTP SCTP 传输协议IPPROTO_TIPC TIPC 传输协议
2. bind 绑定IP端口
功能用于绑定IP地址和端口号到sockfd
函数原型 #include sys/types.h #include sys/socket.hint bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//成功返回0失败返回-1参数分析
参数类型/值sockfd服务端网络标识符即 socket 的返回值struct sockaddr *addr绑定服务器端 网络协议、IP 地址和端口号的地址结构指针socklen_t addrlen结构体大小
addr 一个指向包含有本机 IP 地址及端口号等信息的 sockaddr 类型的指针指向要绑定给 sockfd 的协议地址结构这个地址结构根据地址创建socket 时的地址协议族的不同而不同
注 IPV4的实际结构体如下
struct sockaddr {sa_family_t sa_family;char sa_data[14];
}同等替换为 struct sockaddr_in {sa_family_t sin_family; //协议族in_port_t sin_port; //端口号struct in_addr sin_port; //IP地址结构体unsigned char sin_zero[8]; //填充 无实际意义};struct sockaddr_in 结构体已在Linux内核系统中定义成员参数配置如下; sa_family_t sin_family 协议族, TCP协议族AF_INET in_port_t sin_port 端口号 类型为网络字节序需利用htons函数进行转化为网络字节数 例s_addr.sin_port htons(8888); struct in_addr sin_port IP地址结构体struct in_addr 类型结构体 系统中定义的struct in_addr 结构体 struct in_addr {__be32 s_addr;};将IP地址转化为网络能识别的格式函数原型 #include netinet/in.h#include arpa/inet.hint inet_aton(const char* straddr,struct in_addr *addrp);转化典例 inet_aton(127.0.0.1, s_addr.sin_addr );地址转化API int inet_aton(char *straddr,struct in_addr *addr)//将字符串形式的127.0.0.1转化为网络能识别的格式char *inet_ntoa(struct in_addr inaddr);//把网络格式的ip地址转化为字符串形式结构体配置及bin函数整合实例 struct sockaddr_in s_addr; //结构体变量定义s_addr.sin_family AF_INET; //配置网络协议族TCP协议inet_aton(127.0.0.1, s_addr.sin_addr ); //配置结构体成员IP地址s_addr.sin_port htons(8888); //配置结构体成员端口号bind(s_fd, (struct sockaddr *)s_addr, sizeof(struct sockaddr_in)); //绑定IP端口号3. listen 监听客户端
函数原型 #include sys/types.h /* See NOTES */#include sys/socket.hint listen(int sockfd, int backlog);参数分析
参数类型/值sockfd服务端网络标识符backlog允许的最大客户单请求个数
功能
设置能处理的最大连接数listen()并未开始接受连线只是设置 socket 的 listen 模式listen 函数只用于服务器端服务器进程不知道要与谁连接因此它不会主动地要求与某个进程连接只是一直监听是否有其他客户进程与之连接然后响应该连接请求并对它做出处理一个服务进程可以同时处理多个客户进程的连接。主要就两个功能将一个未连接的套接字转换为一个被动套接字监听规定内核为相应套接字排队的最大连接数。内核为任何一个给定监听套接字维护两个队列: 未完成连接队列每个这样的 SYN 报文段对应其中一项已由某个客户端发出并到达服务器而服务器正在等待完成相应的 TCP 三次握手过程。这些套接字处于SYN REVD 状态已完成连接队列每个已完成 TCP 三次握手过程的客户端对应其中一项。这些套接字处于ESTABLISHED 状态
4. accept 接收客户端
函数原型 #include sys/types.h /* See NOTES */#include sys/socket.hint accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);返回值 成功返回接入的客户端网络标识符失败返回-1 参数分析
参数类型/值sockfd服务端网络标识符struct sockaddr *addrstruct sockaddr 结构体类型地址用来返回已连接的对端(客户端)的协议地址socklen_t *addrlen客户端地址长度但为地址需先取长度后取地址
例 addrlen sizeof(struct sockaddr_in);c_fd accept(s_fd, (struct sockaddr *)c_addr, addrlen);5. read / write 数据传输 #include unistd.hssize_t read(int c_fd, void *buf, size_t count);ssize_t write(int c_fd, const void *buf, size_t count); 函数使用方法同Linux文件编程用法参数主要为网络标识符、读写Buf以及读写字节数详情请参考博文Linux系统编程—文件API编程
客户端
1. socket 创建套接字
函数原型 #include sys/types.h #include sys/socket.hint socket(int domain, int type, int protocol);返回值 成功返回网络标识符失败返回 -1 参数分析
domain: 指明所使用的协议族通常为AF_INET表示互联网协议族TCP/IP协议族type: 指定socket类型SOCK_STREAM 流式套接字提供可靠的、面向连接的通信流它使用 TCP 协议protocol: 通常赋值 0 选择 type 类型对应的默认协议
2. connect 连接服务
功能该函数用于绑定之后的client 端(客户端)与服务器建立连接
函数原型 #include sys/types.h /* See NOTES */#include sys/socket.hint connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//成功返回0失败返回-1参数分析
参数类型/值sockfd服务端网络标识符struct sockaddr *addr服务器端的 IP 地址和端口号的地址结构指针socklen_t addrlen地址长度常被设置为 sizeof(struct sockaddr_in)
结构体实际配置同服务端案例如下 struct sockaddr_in c_addr; //定义结构体变量c_addr.sin_family AF_INET; //配置成员网络协议族inet_aton(127.0.0.1, c_addr.sin_addr ); //配置结构体成员IP地址c_addr.sin_port htons(8888); //配置结构体成员端口号connect(c_fd, (struct sockaddr *)c_addr, sizeof(struct sockaddr_in)); //绑定IP端口号3. read / write 数据传输 #include unistd.hssize_t read(int c_fd, void *buf, size_t count);ssize_t write(int c_fd, const void *buf, size_t count); 函数使用方法同Linux文件编程用法参数主要为网络标识符、读写Buf以及读写字节数
server.c与client.c程序案例
server.c
#include stdio.h
#include sys/types.h /* See NOTES */
#include sys/socket.h
#include stdlib.h
#include netinet/in.h
#include arpa/inet.h
#include stdlib.h
#include string.h
#include unistd.h
int main()
{int s_fd, c_fd; //定义网络标识符int nread; //读取字节数char readBuf[128]{0}; //读取缓存char msg[]Return from server: I got your message!; //发送缓存//定义网络结构体并初始化struct sockaddr_in s_addr;struct sockaddr_in c_addr;memset(s_addr, 0, sizeof(struct sockaddr_in));memset(c_addr, 0, sizeof(struct sockaddr_in));//1. socket 创建套接字s_fd socket(AF_INET, SOCK_STREAM, 0); //创建套接字if(s_fd -1){printf(socket error!\n);exit(-1);}//2.bind 绑定IP端口号s_addr.sin_family AF_INET; //配置网络协议inet_aton(127.0.0.1, s_addr.sin_addr ); //配置IP地址s_addr.sin_port htons(8888); //配置端口号bind(s_fd, (struct sockaddr *)s_addr, sizeof(struct sockaddr_in)); //绑定IP端口号//3.linsten 监听客户端接入listen(s_fd, 10);printf(listing......\n);//4.accept 接收客户端接入int addrlen sizeof(struct sockaddr_in);c_fd accept(s_fd, (struct sockaddr *)c_addr, addrlen);if(c_fd -1){printf(c_fd error!\n);exit(-1);}elseprintf(connect client: %s\n,inet_ntoa(c_addr.sin_addr));//5.read memset(readBuf, \0, 128);nread read(c_fd, readBuf, 128); //从客户端读取128字节数据到readBuf缓存if(nread -1){printf(nread error\n);exit(-1);}printf(Receive: %d Byte context:%s\n,nread, readBuf);//6.writewrite(c_fd, msg, strlen(msg)); //应答客户端memset(msg,\0,128);return 0;
}client.c
#include stdio.h
#include sys/types.h /* See NOTES */
#include sys/socket.h
#include stdlib.h
#include netinet/in.h
#include arpa/inet.h
#include stdlib.h
#include string.h
#include unistd.hint main()
{int c_fd;int nread;int addrlen;char readBuf[128]{0};char msg[]hello world;struct sockaddr_in c_addr;memset(c_addr, 0, sizeof(struct sockaddr_in));//1. socketc_fd socket(AF_INET, SOCK_STREAM, 0);if(c_fd -1){printf(socket error!\n);exit(-1);}//2. connect 与服务器建立连接c_addr.sin_family AF_INET;inet_aton(127.0.0.1, c_addr.sin_addr );c_addr.sin_port htons(8888);if( connect(c_fd, (struct sockaddr *)c_addr, sizeof(struct sockaddr_in)) -1){printf(connect error\n);exit(-1);}//3.writewrite(c_fd, msg, strlen(msg));memset(msg, \0, 128);//4.readmemset(readBuf,\0,128);nread read(c_fd, readBuf, 128);if(nread -1){printf(nread error\n);exit(-1);}printf(read from server: %d Byte context:\n%s\n,nread, readBuf);return 0;
}试问如何实现双方自由聊天
服务器通过创建子进程用于和每个不同的客户端进行数据交互父进程负责接收后续接入的客户端子进程内部再次创建子进程用来发送数据父进程则实时接收来自服务器的数据
server.c 核心代码
//4.accept
while(1)
{//父进程用于接收其他接入的客户端c_fd accept(s_fd, (struct sockaddr *)c_addr, addrlen);if(c_fd -1){printf(c_fd error!\n);exit(-1);}elseprintf(connect client: %s\n,inet_ntoa(c_addr.sin_addr));cnt;if(fork() 0) //创建进程子进程用于和客户端进行数据交互{if(fork() 0) //子进程用于向客户端发送数据{//writewhile(1){printf(Inputs: );scanf(%s,msg);write(c_fd, msg, strlen(msg));memset(msg,\0,128);}}else //父进程用于接收来自客户端发送的数据{//readwhile(1){memset(readBuf, \0, 128);nread read(c_fd, readBuf, 128);if(nread -1){printf(nread error\n);exit(-1);}printf(Receive: %d Byte context:%s\n,nread, readBuf);}}}
}client.c 核心代码
while(1)
{if(fork() 0) //子进程用于向服务器发送数据{while(1) //write{printf(Input: );scanf(%s,msg);//gets(msg);write(c_fd, msg, strlen(msg));memset(msg, \0, 128);}}else { //父进程用于接收服务器发送的数据while(1) //read {memset(readBuf,\0,128);nread read(c_fd, readBuf, 128);if(nread -1){printf(nread error\n);exit(-1);}printf(read from server: %d Byte context:\n,nread);printf(%s\n,readBuf);}
}