今天老大给了任务。。让了解socket编程。。
百度了解了资料。。下面给出socket的模型。。
这个就是socket的总设计流程拉。。
大概的说明一下。。网络嘛。。肯定是通信。。通信就不是一台机器了。。要多台。。这里举例最简单的两台。。
其中这里的通信并不是指双方都是用户的那种通信。。二是有一个服务器和一个客户机之间的类似上下级之间 的通信。。
这里先说明一下服务器的流程。。服务器机器需要先执行socket函数。。相当于创建了一个socket。。简单的理解为就是open打开了一个文件描述符的差不多意思。。后续操作都要用到这个描述符。。
int socket(int domain, int type, int protocol);
其中第一个参数是协议域。。第二个参数是指定的socket类型。。第三个参数是指定的协议。。返回值就是一个文件描述符了
socket结束之后。。要调用到bind函数。。既然我们上一个函数的参数值都是些协议什么的。。所以返回的描述符就相当于有一个框架但是没有具体的内容。。bind函数就是赋予它实际的内容。。给他地址啊端口啊什么的。。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);这里的第一个参数就是刚才socket的返回描述符。。第二个参数是一个结构体指针。。第三个是这个结构体长度。。
这里重点的就是这个结构体了。。这是一个struct sockaddr_in类型的结构体。。这个结构体是不需要我们创建的。。头文件里面有。。我这里使用的是ipv4的类型。。里面有三个参数
struct sockaddr_in { sa_family_t sin_family; /* 地址的协议域: 如AF_INET */ in_port_t sin_port; /* 要监听的端口 */ struct in_addr sin_addr; /* 地址结构体 */ };struct in_addr { uint32_t s_addr; /* 服务器地址 */ };这里虽然是两个参数加一个结构体。。但是这个结构体只有一个参数。。就姑且简单的理解为三个参数这三个参数的大概意思就是这样了。。这里说明一下要监听的端口。。我最一开始接触的时候有这样一个疑问。。通信有ip地址就好了为什么要端口。。可能用过SecureCRT的同学会有点印象。。我们用CRT远程登录时候会有要填写端口和ip地址。。其实我们在网络通信时候。。找到ip地址只是相当于找到了要去的地方。。但是具体怎么进去。。就是要通过端口这个通道。。简单来说ip就相当于一栋大楼。。而端口就相当于是这个大楼的各个大门现在socket和bind之后。。我们的服务器就相当于建立好了。。这个时候就等待客户端连接了。。当客户端发来请求怎么发现呢。。这里就会用到一个listen函数。。用来监听客户端int listen(int sockfd, int backlog);第一个参数就是刚才的socket描述符。。第二个参数是允许最大的等待队列。。就是可以同时满足的客户数。。超过这个数量就不能正常的接受客户机请求。。除了监听是否有用户发来请求之外。。还需要知道用户的地址情况是什么。。这两者是缺一不可的。。但是确实由两个函数完成的。。int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);这个函数是获取用户请求的。。第一个参数是之前打开的描述符。。第二个参数是客户端地址。。第三个是地址长度。。这里要说明的有两点。。一是返回值。。二是阻塞先说一下返回值。。这里参数中有一个描述符。。而返回值也是一个类似于描述符的数值。。这两个描述符是不一样的。。参数里的是服务器描述符。。是从你打开服务器。。也就是socket创建的服务器描述符。。是一直在服务器运行期间都存在的。。二这个返回的描述符。。是针对某个用户请求专门设置的描述符。。也就是说这个描述符专门用来处理这个客户机的请求。。在这个客户请求退出之后就退出释放了。。理解的话就相当于10010和1号话务员。。10010是一直存在的。。而1号话务员只是在你有请求时候的特殊时间段属于你这个客户的。。下面说说阻塞。。之前说过这两个函数的功能是不肯分割的。。二这两个函数的功能是监听。。如果没有客户接进来的时候呢。。肯定不能一直while循环检测。。这里就涉及到了阻塞。。强调的是阻塞是发生在整个监听功能之后的。。也就是说在accept函数之后会有阻塞。。在listen之后没有阻塞。。当连接好了之后。。也就进入到通信环节了。。就相当于两个人在通信。。类似于read,write的感觉。。这里就不详细介绍了。。最后就是要加上close函数关闭socket函数生成的描述符。。下面讲述一下客户机流程。。客户机首先也是要socket。。产生一个框架。。之后的connect是要与主机进行连接。。这里的第一个参数是客户机打开的描述符。。第二个是结构体。。第三个是结构体长度。。int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);这里说明的是结构体里面的ip地址。。这个ip是服务器地址。。不是自己本身的地址了。。这就要求我们连接时候需要知道是哪个主机ip。。这是肯定的。。我们要连接服务器肯定知道服务器ip。。但是我们知道的ip通常是192.168.1.1这种形式的。。可以用inet_pton函数转化一下。。连接上之后就是readwrite函数了。。之后就是close函数。。这里给出一个例子。。实现的功能是客户机传给主机一个字符串。。主机打印显示。。主机函数#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/socket.h> #include<sys/types.h> #include<netinet/in.h> #define MAXLINE 4096 int main(int argc, char** argv) { int listenfd, connfd; struct sockaddr_in servaddr; char buff[4096]; int n; if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("create socket error:%s(errno:%d)\n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(6666); if((bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) == -1) { printf("bind error:%s(errno:%d)\n", strerror(errno), errno); exit(0); } if (listen(listenfd, 10) == -1) { printf("listen socket error:%s(errno:%d)\n", strerror(errno), errno); exit(0); } printf("=================waiting for client's request=====================\n"); while(1) { if((connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1) { printf("accept error:%s(errno:%d)\n", strerror(errno), errno); continue; } n = recv(connfd, buff, MAXLINE, 0); buff[n] = '\0'; printf("recv msg from client:%s\n", buff); close(connfd); } close(listenfd); }客户端代码为#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #define MAXLINE 4096 int main(int argc, char **argv) { int sockfd, n; char recvline[4096], sendline[4096]; struct sockaddr_in servaddr; if (argc != 2) { printf("usage: ./client<ipaddress>\n"); exit(0); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("create socket error: %s(errno: %d)\n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(6666); if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) { printf("inet_pton error for %s\n",argv[1]); exit(0); } if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) <0 ) { printf("connect error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("send msg to server: \n"); fgets(sendline, 4096, stdin); if(send(sockfd, sendline, strlen(sendline), 0) <0 ) { printf("send msg error: %s(errno: %d)\n", strerror(errno), errno); exit(0); } close(sockfd); return 0; }这里强调的是socket之前要确保两个机器是可以ping的通的。。ping不通都没有网络怎么通信。。
这里参考了http://blog.youkuaiyun.com/gneveek/article/details/8699198的微博。。特别感谢这个大神