【学习笔记】天嵌2440第三季下学期——linux tcp网络编程
来源:互联网 发布:软件行业的进项 编辑:程序博客网 时间:2024/06/07 20:02
tcp网络编程模型:
客户端的流程:
(1)创建套接字(socket)
(2)向服务器发出连接请求(connect)
(3)和服务器端进行通信(send/recv)
(4)关闭套接字(close)
服务器端的流程如下:
(1)创建套接字(socket)
(2)将套接字绑定到一个本地地址和端口上(bind)
(3)将套接字设为监听模式,准备接收客户端请求(listen)
(4)等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)
(5)用返回的套接字和客户端进行通信(send/recv)
(6)循环或关闭套接字。(close)
函数情况:
(一)创建套接字socket连接:
#include <sys/types.h> #include <sys/socket.h>int socket(int domain, int type, int protocol);
参数:
domain指明了协议簇:
Name Purpose Man pageAF_UNIX, AF_LOCAL Local communication unix(7)AF_INET IPv4 Internet protocols ip(7)AF_INET6 IPv6 Internet protocols ipv6(7)AF_IPX IPX - Novell protocolsAF_NETLINK Kernel user interface device netlink(7)AF_X25 ITU-T X.25 / ISO-8208 protocol x25(7)AF_AX25 Amateur radio AX.25 protocolAF_ATMPVC Access to raw ATM PVCsAF_APPLETALK AppleTalk ddp(7)AF_PACKET Low level packet interface packet(7)AF_ALG Interface to kernel crypto API
其中AF_INET代表ip4
SOCK_STREAM Provides sequenced, reliable, two-way, connection-basedbyte streams. An out-of-band data transmission mechanism may be supported.SOCK_DGRAM Supports datagrams (connectionless, unreliable messages of a fixed maximum length).SOCK_SEQPACKET Provides a sequenced, reliable, two-way connectionbased data transmission path for datagrams of fixed maximum length; a consumer is required to read an entire packet with each input system call.SOCK_RAW Provides raw network protocol access.SOCK_RDM Provides a reliable datagram layer that does not guarantee ordering.SOCK_PACKET Obsolete and should not be used in new programs; see packet(7).其中SOCK_STREAM代表有序、可靠、双向的面向连接字节流(即tcp)
SOCK_DGRAM代表长度固定的、无连接的不可靠的保温传递(即udp)
protocol当存在多个协议时,默认使用的协议。通常取0。
(二)绑定地址:bind
#include <sys/types.h> #include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);参数:
sockfd:socket返回的套接字id
addr:保存绑定的地址:
struct sockaddr_in { sa_family_t sa_family; //协议族[1] char sa_family[14]; //地址[14]};
这是通用的地址结构体;
下面的时tcp专用的地址结构体,两者的长度一致,形式不同:
struct sockaddr_in {sa_family_t sin_family;//协议族[1]in_port_t sin_port;//端口号[2]struct in_addr sin_addr;//ip地址[4]char sin_zero[8];//填充字节[8],共[15]};其中ip地址结构体struct in_addr的定义为:
struct in_addr {in_addr_t s_addr; };len:地址的长度:
sizeof(struct sockaddr_in);
(三)ip地址的数据类型
由于ip是由4位16进制数组成,“10.0.2.15”时字符串型,这里存在字符串与整形的变换:字符串转化为整形:
in_addr_t inet_addr(const char *cp);参数是char型,返回值是struct in_addr中的成员:in_addr_t型的s_addr;
整形转化为字符串型:
char *inet_ntoa(struct in_addr in);参数是结构体struct in_addr,可见上下两个函数并不对等;
注意,上面两种函数涉及的数据形式都是网络字节序,大端!
(四)网络字节序
由于网络数据传输存在先后顺序,所以产生字节序问题网络字节序都是大端
主机字节序不定,有大端也有小端
头文件:
#include <arpa/inet.h>
发送方:由主机->网络字节序
uint32_t htonl(uint32_t hostlong);uint16_t htons(uint16_t hostshort);
发送方:由网络->主机字节序
uint32_t ntohl(uint32_t netlong);uint16_t ntohs(uint16_t netshort);
其中:in_addr.s_addr=htonl(INADDR_ANY)指代服务器可接受主机一切网络设备(ip)上传来的请求
(五)监听设备:listen
#include <sys/types.h> #include <sys/socket.h>int listen(int sockfd, int backlog);
参数:
sockfd:socket返回的套接字id;
backlog:接收客户机的数量
返回值:success:0
error:-1
(六)等待连接:accept
#include <sys/types.h> #include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
sockfd:socket返回的套接字id;
addr:保存绑定的地址:
addrlen:addr长度的指针,注意,这里是指针!必须取地址赋值!
返回值:success:新的套接字id
error:-1
(七)发送数据:send
#include <sys/types.h>#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);
参数:
sockfd:socket返回的套接字id;
buf:数据存放的地址,指针
len:数据长度
flags:发送选项,通常取0
返回值:success:新的套接字id
error:-1
(八)接收数据:recv
#include <sys/types.h>#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数:
sockfd:socket返回的套接字id;
buf:数据存放的地址,指针
len:数据长度
flags:发送选项,通常取0
返回值:success:新的套接字id
error:-1
(九)客户端连接:connect
#include <sys/types.h> #include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd:socket返回的套接字id;
addr:保存绑定的地址:
addrlen:addr长度的指针,注意,这里是不是指针!跟accept不一样!
上代码:
tcp_server.c:
#include <stdio.h>#include <sys/socket.h>#include <string.h>#include <netinet/in.h>#define portnum 2333void main(){int sockfd, new_fd;struct sockaddr_in server_addr;struct sockaddr_in client_addr;char buffer[128];int nbyte;int size_addr;//1、创建套接字if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){printf("sockfd create error!\n");exit(1);}//2.1、设置绑定地址bzero(&server_addr, sizeof(struct sockaddr_in));//清零server_addr结构server_addr.sin_family = AF_INET;server_addr.sin_port = htons(portnum);//转换套接字server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//2.2、绑定地址bind(sockfd, (struct sockaddr *) (&server_addr), sizeof(struct sockaddr));//3、监听端口listen(sockfd, 5);while (1){//4、等待连接,忽略对new_fd的判断验证size_addr=sizeof(struct sockaddr);new_fd = accept(sockfd, (struct sockaddr *) (&client_addr), &size_addr);printf("server get connection from %s,%d\n", inet_ntoa(client_addr.sin_addr),client_addr.sin_addr.s_addr);//5、接受数据nbyte=recv(new_fd, buffer, 128, 0);buffer[nbyte] = '\0';printf("server received is %s\n", buffer);//6、结束连接close(new_fd);}close(sockfd);return 1;}tcp_client.c:
#include <stdio.h>#include <sys/socket.h>#include <string.h>#include <netinet/in.h>#define portnum 2333int main(){int sockfd;struct sockaddr_in server_addr;char buffer[128];//1、创建套接字if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){printf("sockfd create error!\n");exit(1);}//2.1、设置绑定地址bzero(&server_addr, sizeof(struct sockaddr_in));//清零server_addr结构server_addr.sin_family = AF_INET;server_addr.sin_port = htons(portnum);//转换套接字server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");printf("the distance is %s",inet_ntoa(server_addr.sin_addr));//2.2、连接到服务器if (connect(sockfd, (struct sockaddr *) (&server_addr), sizeof(struct sockaddr)) == -1){printf("connect error!\n");exit(1);}//3、发送数据到服务器printf("please enter char:\n");fgets(buffer, 128,stdin);send(sockfd, buffer, strlen(buffer), 0);//4、关闭连接close(sockfd);return 1;}期间遇到很多莫名其妙的问题,客户端一致无法连接,服务器又不停滴接收到来自0.0.0.0的通讯,后者莫名其妙地解决了,至今不知道是什么原因导致的,前者gdb调试+百度谷歌仍然找不出原因,随后从网上找来被人的代码对比试验:
http://blog.csdn.net/chocolate001/article/details/6612201经过两天前前后后的探寻才终于发现原因:
((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)问题出在这句话上,一开始粗心,写成了:
(sockfd = socket(AF_INET, SOCK_STREAM, 0) == -1)因为==的优先级高于=,所以结果肯定是出错了,因而倒是无法识别正确的id(或者说fd)更准确些。
接下来优化服务器代码:
通过把第五第六步(数据处理和结束连接)放到子进程中执行,实现服务器对多个客户端同时访问的请求。
#include <stdio.h>#include <sys/socket.h>#include <string.h>#include <netinet/in.h>#define portnum 2333void main(){int sockfd, new_fd;struct sockaddr_in server_addr;struct sockaddr_in client_addr;char buffer[128];int nbyte,pid;int size_addr;//1、创建套接字if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){printf("sockfd create error!\n");exit(1);}//2.1、设置绑定地址bzero(&server_addr, sizeof(struct sockaddr_in));//清零server_addr结构server_addr.sin_family = AF_INET;server_addr.sin_port = htons(portnum);//转换套接字server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//server_addr.sin_addr.s_addr = inet_addr("10.0.2.15");//2.2、绑定地址bind(sockfd, (struct sockaddr *) (&server_addr), sizeof(struct sockaddr));//3、监听端口listen(sockfd, 5);while (1){//4、等待连接,忽略对new_fd的判断验证size_addr=sizeof(struct sockaddr);new_fd = accept(sockfd, (struct sockaddr *) (&client_addr), &size_addr);printf("server get connection from %s,%d\n", inet_ntoa(client_addr.sin_addr),client_addr.sin_addr.s_addr);//create child fork immdiatelyif(pid=fork()==0){//5、接受数据nbyte=recv(new_fd, buffer, 128, 0);buffer[nbyte] = '\0';printf("server received is %s\n", buffer);close(new_fd);close(sockfd);exit(0);}else if(pid<0)printf("fork error!\n");//6、结束连接close(new_fd);}close(sockfd);return 1;}
阅读全文
0 0
- 【学习笔记】天嵌2440第三季下学期——linux tcp网络编程
- 【学习笔记】天嵌2440第三季下学期——linux消息队列编程
- 【学习笔记】天嵌2440第三季下学期——linux共享内存通讯
- 【学习笔记】天嵌2440第三季下学期——linux多线程互斥
- 【学习笔记】天嵌2440第三季下学期——linux多线程同步
- Linux-网络编程学习笔记之tcp
- (53)Java学习笔记——网络编程 / TCP协议
- Linux网络编程-学习笔记(基础TCP套接字函数)
- Linux网络编程--TCP的套接字通信学习笔记
- linux程序设计(套接字)+TCP/IP网络编程学习笔记
- Linux网络编程学习笔记-TCP/IP基础-1
- Linux 网络编程——TCP编程
- 大二下学期学习总结
- 下学期第三周实验报告2
- 下学期第三周实验报告3.2
- 下学期第三周实验报告4
- Linux 网络编程——TCP
- linux网络编程——TCP文件服务器
- mysql 优化实战
- linux 内核信号量 用户态信号量 详解
- utf-8 去掉中文标点符号
- 滑块运动 — 到目标位置宽度缓慢展开
- 并发编程实战死锁读书笔记之吐槽
- 【学习笔记】天嵌2440第三季下学期——linux tcp网络编程
- Linux中三种网络模式是什么意思——bridged(一桥接模式)
- echarts 地图区域无法显示
- CSS visibility占位隐藏属性
- Mybatis Generator最完整配置详解
- swift_038(Swift之guard关键字(守护))
- ios之Autolayout的运用
- Makefile详解(一)
- poi操作excel文件