您的位置:首页 > 编程语言

套接字编程1 ------ 涉及的主要API函数 - 1

2017-12-20 02:10 225 查看
TCP进行通信的过程(三次握手):

连接的发起段(通常称为客户端),向目标计算机(通常称为服务器)发送一个请求建立连接的数据包。
服务器收到请求后,对客户端的同步信号做出响应、发送自己的同步信号给客户端。
客户端对服务器端发来的同步信号进行响应。至此,连接建立完成,就可以进行数据传输了。

TCP连接的关闭:

请求主机发送一个关闭连接的请求给另一方。
另一方收到关闭连接的请求后,发送一个接收请求的确认数据包,并关闭它的socket连接。
请求主机收到确认数据包后,发送一个确认数据包,告知另一方其发送的确认信息已收到,同时请求主机关闭它的socket连接。

套接字地址结构
      结构struct sockaddr_in定义了TCP/IP协议族的套接字地址格式,定义如下:
#include <netinet/in.h>
struct sockaddr_in{
unsigned short            sin_family;      //地址类型
unsigned short int       sin_port;      //端口号
struct in_addr             sin_addr;      //IP地址
unsigned char             sin_zero[8];      //填充字节,一般赋值为0
};


      sin_family表示地址类型,对于使用TCP/IP协议进行的网络编程,该值只能是AF_INET。
      sin_addr用来存储32位的IP地址,定义如下:

struct in_addr{
unsigned long      s_addr;
};


      设置地址信息的示例代码:

......
struct sockaddr_in sock;
sock.sin_family=AF_INET;
sock.sin_port=htons(80);    //设置端口
sock.sin_addr.s_addr=inet_addr("202.205.3.195");    //设置IP地址
memset(sock.sin_zero,0,sizeof(sock.sin_zero));    //将数组sin_zero设置为0


创建socket套接字
      通过调用函数socket创建套接字。以下示例代码创建了一个TCP套接字:
int sock_fd;
sock_fd=socket(AF_INET,SOCK_STREAM,0);      //SOCK_STREAM代表创建TCP套接字
if(sock_fd < 0){
perror("socket error\n");
exit(1);
}


      创建UDP协议的套接字为:

sock_fd = socket(AF_INET, SOCK_DGRAM, 0);

建立连接
      connect函数的原型:

#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);


      函数connect用来在一个指定的套接字上创建一个连接,服务器的IP地址和端口号由参数serv_addr指定。通常一个面向连接的套接字(TCP套接字)只能调用一次connect函数,用于向服务器发出连接请求。而对于无连接的套接字(UDP套接字),connect函数并不建立真正的连接,它只是告诉内核与该套接字进行通信的目的地址,只有该目的地址发来的数据才会被socket接收。所以UDP套接字可以多次调用connect函数来改变与目的地址的绑定。

      connect函数的用法示例:

......
if(connect(sock_fd,(struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in)) <0){
perror("connect error\n");
exit(1);
}


      注意:须将serv_addr强制转换为struct sockaddr类型。

绑定套接字
      函数bind用来将一个套接字和某个端口绑定的一起。原型:

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);


      socket函数只是创建了一个套接字,它将工作在哪个端口上,程序尚未指明。因此需要用bind函数将一个套接字和某个端口绑定在一起。

      参数my_addr指定了sockfd将绑定到的本地地址,可以将my_addr的sin_addr设置为INADDR_ANY而不是某个确定的IP地址就可以绑定到任何网络接口。对于只有一个IP地址的计算机,对应的就是它的IP地址;对于有多块网卡的计算机,INADDR_ANY表示将处理来自所有网络接口上相应端口的连接请求。

      bind函数的典型用法:

struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(struct sockaddr_in));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(80);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

if(bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in)) <0){
perror("bind error\n");
exit(1);
}

监听套接字
      调用函数listen对套接字进行监听。
#include <sys/socket.h>
int listen(int s, int backlog);


      由函数socket创建的套接字是主动套接字,可以用来主动请求连接到某个服务器(通过connect函数)。但是作为服务器端的程序,通常在某个端口上监听等待来自客户端的连接请求。在服务器端,一般是先调用函数socket创建一个主动套接字,然后调用函数bind将该套接字绑定到某个端口上,接着再调用函数listen将该套接字转化为监听套接字,等待来自客户端的连接请求。

      该函数典型用法:

#define LISTEN_NUM 12      //定义连接请求队列长度
......
if(listen(sock_fd,LISTEN_NUM) <0){
perror("listen error\n");
exit(1);
}

接收连接
      用accept函数来接受一个连接请求。

#include <sys/types.h>
#include <sys/socket.h>
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

参数s是由socket创建、经函数bind绑定到本地某一端口上,然后通过函数listen转化而来的监听套接字。
参数addr用以保存发起连接请求的主机的地址和端口。
参数addrlen是addr所指向的结构体的大小。
      只能对面向连接的套接字使用accept函数,此函数执行成功返回一个新的代表客户端的套接字,出错返回-1。进程可以利用这个新的套接字描述符与客户端交换数据。参数s所指定的套接字继续等待客户端的连接请求。

      参数s所指定的套接字默认被设置为阻塞方式,accept()函数将被阻塞直到有连接请求到达为止。常见用法:

int client_fd;
int client_len;
struct sockaddr_in client_addr;
......
client_len=sizeof(struct sockaddr_in);
client_fd=accept(sock_fd, (struct sockaddr *)&client_addr, &client_len);
if(conn_fd < 0){
perror("accept");
exit(1);
}

TCP套接字发送数据

      send()用来在TCP套接字上发送数据。
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int s, const void *msg, size_t len, int flags);

函数send只能对处于连接状态的套接字使用。
参数s为已建立好连接的套接字描述符,即accept函数的返回值。
参数msg指向存放待发送数据的缓冲区。
参数len为待发数据的长度。
参数flags为控制选项,一般设置为0。

      执行成功返回实际发送数据的字节数,出错返回-1。注意,执行成功只是说明数据写入套接字的缓冲区,并不表示数据已经成功地通过网络发送到目的地。
      send函数的常见用法:
#define BUFFERSIZE 1500
char send_buf[BUFFERSIZE];
......
if(send(conn_fd, send_buf, len, 0) < 0){
perror("send error\n");
exit(1);
}

接收数据

      函数recv用来在TCP套接字上接收数据。其原型:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int s, void *buf, size_t len, int flags);


      recv从参数s所指定的套接字描述符(必须是面向连接的套接字)上接收数据并保存到参数buf所指定的缓冲区,参数len为缓冲区长度。参数flags为控制选项,一般设置为0。如果在指定的套接字上无数据到达时,recv()将被阻塞。
      执行成功返回接收到的数据字节数,出错则返回-1。
      该函数常见用法:
char recv_buf[BUFFERSIZE];
......
if(recv(conn_fd, recv_buf, sizeof(recv_buf), 0) < 0){
perror("recv");
exit(1);
}

UDP套接字发送数据

      函数sendto用来在UDP套接字上发送数据。原型:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);


      函数sendto与函数send类似,但它不需要套接字处于连接状态。因为是无连接的套接字,所以在使用时需要制定数据的目的地址。

参数msg指向待发送数据的缓存区
参数len指定了待发数据的长度
参数flags控制选项,一般设置为0
参数to用于指定目的地址
参数tolen指定目的地址的长度

UDP套接字接收数据

      recvfrom用来在UDP套接字上接收数据。其原型:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);


      函数recvfrom与函数recv功能类似,只是recv只能用于面向连接的套接字。

参数buf指向接收缓冲区
参数len指定了缓冲区的大小
参数flags控制选项,一般设置为0
参数from中保存数据的源地址
参数fromlen在调用recvfrom前为参数from的长度,调用recvfrom后将保存from的实际大小

      执行成功返回实际接收数据的字节数,出错则返回-1。

关闭套接字

      函数close用来关闭一个套接字描述符,它与关闭文件描述符是类似的。
#include <unistd.h>
int close(int fd);

参数fd为一个套接字描述符,该函数关闭一个套接字。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C c语言 套接字 TCPIP