您的位置:首页 > 理论基础 > 计算机网络

初步实现网络socket编程

2016-04-02 13:09 597 查看
今天老大给了任务。。让了解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
= '\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.csdn.net/gneveek/article/details/8699198的微博。。特别感谢这个大神
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: