使用TCP套接字编程可以实现基于TCP/IP协议的面向连接的通信,它分为服务端(Server)和客户端(Client)两个部分,具体流程图如下所示:
流程图.png
现在就基本套接字函数做学习笔记:
socket()函数
为了执行I/O,无论是服务端还是客户端,首先必须调用socket()函数,产生TCP套接字,作为TCP通信的传输端点。
#include <sys/socket.h>
int socket(int family,int type,int protocol);
该函数调用成功,则返回一个小的非负的整数值,失败则返回-1;
family参数指明协议族,它的值常用为:
family=AF_INET;//IPv4协议;
family=AF_INET6;//IPv6协议;
family=AF_ROUTE;//路由套接口。
type参数指明产生套接字的类型,它的值常用为:
type=SOCK_STREAM;//字节流套接口,TCP常用的形式;
type=SOCK_DGRAM;//数据报套接口,UDP常用的形式 ;
type=SOCK_RAW;//原始套接口
protocol参数是协议标志,一般在调用socket()函数时将其设置为0。(但如果是原始套接字,就需要为其指定一个常值)
//eg:调用socket()函数
#include <sys/socket.h>
...
int sockfd;
//crteate socket
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
//handle exception
...
}
bind()函数
绑定函数的作用就是为调用socket()函数产生的套接字分配一个本地协议地址,建立地址与套接字的对于关系。
#include <sys/socket.h>
int bind(int sockfd,const struct sockaddr *server,socklen_len addrlen);
该函数调用成功返回0,若出错则返回-1,并置错误号errno;
sockfd参数是套接字函数返回的套接字描述符;
server参数是指向特定于协议的地址结构的指针,指定用于通信的本地协议地址;
addrlen参数是指定该套接字地址结构的长度;
//eg: 调用bind()函数
#include <sys/socket.h>
...
int sockfd;
int port = 1234;//bind 的端口号是1234
struct sockaddr_in server;
...
//对服务器的地址结构初始化赋值,IP地址是一个通配地址,由内核选择。
bzero(&server,sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
//调用bind()函数将描述符sockfd与server套接字地址结构中的协议地址绑定
if(bind(sockfd,(struct sockaddr *)&server,sizeof(server)) == -1)
{
//handle exception
//如果调用失败,则进行异常处理
...
}
...
listen()函数
监听函数的作用就是将未连接的套接字转换成被动套接字,使它处在监听模式下,指示内核应接受发向该套接字的连接请求。
#include <sys/socket.h>
int listen(int sockfd,int backlog);
该函数调用成功返回0,若出错则返回-1,并置errno值;
sockfd参数是要设置的描述符;
backlog参数规定了请求队列中的最大连接数;
//eg:调用listen()函数
#include <sys/socket.h>
...
int sockfd;
int BACKLOG = 5;//设置监听的最大连接数为5
...
//调用listen()函数,将sockfd描述符设置为监听描述符
if(listen(sockfd,BACKLOG) == -1)
{
//handle exception
//如果调用失败,则进行异常处理
...
}
...
accept()函数
接受函数的作用就是使服务器接受客户端的连接请求。
#include <sys/socket.h>
int accept(int listenfd,struct sokaddr *client,socklen_t *addrlen);
该函数调用成功后,返回三个值:
(1):accept()函数的返回值,已连接套接字描述符;
(2):client参数参会客户端的协议地址,包括IP地址和端口号等;
(3):addrlen参数返回客户端地址结构的大小。
如果调用失败则返回-1,并置errno值。
listenfd参数是由sockfd()函数产生的套接字描述符,在调用accept()函数前,已经调用listen()函数将此套接字变成了监听套接字;
client参数是用来返回连接对方的套接字地址结构;
addrlen参数是用来返回连接对方的套接字的结构长度。
//eg:调用accept()函数
#include <sys/socket.h>
...
int listenfd,connfd;//定义两个套接字描述符,监听套接字描述符和已连接套接字描述符
struct sockaddr_in client;
socklen_t addrlen;
addrlen=sizeof(client);//得到client当前的长度
...
//调用accept()函数,接收连接请求,返回已连接套接字描述符
connfd = accept(listenfd,(struct sockaddr *)&client,&addrlen);
if(connfd == -1)
{
//handle exception
//如果调用失败,则进行异常处理
...
}
...
connect()函数
连接函数的作用就是让TCP客户端使用来配置套接字,建立一个与TCP服务器的连接。(激发TCP的三次握手过程)
#include <sys/socket.h>
int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
该函数调用成功后返回0,若出错则返回-1;
sockfd参数是有sockd()函数返回的套接字描述符;
addr参数是指向服务器的套接字地址结构的指针;
addrlen参数是该套接字地址结构的大小
//eg:调用connect()函数
#include <sys/socket.h>
...
int sockfd;
struct sockaddr_in server;
...
bzero(&server,sizeof(server));//为套接字地址结构server设置初始值0
//位套接字地址结构中的成员复制,客户端要建立链接的服务器IP地址为127.0.0.1,端口号为1234.
server.sin_family = AF_INET;
server.sin_port = htons(1234);
server.sin_addr.s.addr = inet_addr("127.0.0.1");
//调用connect()函数与服务器建立连接
if(connect(sockfd,(struct sockaddr *)&server,sizeof(server)) ==
-1)
{
//handle exception
//如果调用失败,则进行异常处理
...
}
...
数据传输函数:write()和read()函数
当服务器和客户端的连接建立起来后,就可以进行双向的数据传输了。
write()和read()函数
write()函数用于数据的发送:
#include <unistd.h>
int write(int sockfd,char *buf,int len);
该函数调用成功返回大于0的整数,也就是发送的字节数,若出错则返回-1;
buf参数是指向一个用于发送信息的数据缓冲区;
len参数是指明传送数据缓冲区的大小。
read()函数用于数据的接收
#include <unistd.h>
int read(int sockfd,char *buf,int len);
该函数调用成功返回大于0的整数,也就是发送的字节数,若出错则返回-1;
buf参数是指向一个用于接收信息的数据缓冲区;
len参数是指明接收数据缓冲区的大小。
//eg:调用read()函数
#include <unistd.h>
#include <sys/sockfd.h>
#define MAXDATASIZE 100;//定义接收信息的数据缓冲区的长度
...
int num,connfd;
char buf[MAXDATASIZE];
...
//接收数据,整数num返回接收的字节数
if(((num = read(connfd,buf,MAXDATASIZE)) > 0))
{
//handle data
//处理接收到的数据
...
}
...
close()函数
关闭函数的作用就是关闭套接字,并立即返回到进程。
#include <unistd.h>
int close(int sockfd);
下一章开始介绍基本TCP套接字编程实例。
网友评论