基本TCP套接字编程

文章目录

    • 基本流程
    • 相关函数
      • socket()函数
      • connect()函数
      • bind()函数
      • listen()函数
      • accept()函数
    • 函数使用尝试
    • 客户端服务器通信相关函数
      • recv()/send()函数
      • recv()和send()函数使用


基本流程

服务器:

    1. 创建套接字socket()
    1. 填充服务器网络信息结构体(上节记录了)
    1. 将套接字与服务器网络信息结构体绑定bind()
    1. 将服务器设置为监听状态listen()
    1. 阻塞等待客户端的连接accept()
    1. read()/write(), recv()/send(), recvfrom()/sendto()等函数通信
      客户端:
    1. 创建套接字socket()
    1. 填充网络服务器信息结构体
    1. connect()给服务器发送请求
    1. 进行通信
    1. close() 关闭

相关函数

socket()函数

#include 

int socket(int family, int type, int protocol);

创建一个套接字,返回文件描述符,失败返回-1.
family指明协议族可以为以下几种:

  • AF_INET:IPv4协议
  • AF_INET6:IPv6协议
  • AF_LOCAL:Unix域协议
  • AF_ROUTE:路由套接字
  • AF_KEY:秘钥套接字

type指明套接字的类型,可以是

  • SOCKET_STREAM:字节流套接字
  • SOCKET_DGRAM:数据报套接字–UDP
  • SOCKET_SEQPACKET:有序分组套接字
  • SOCKET_RAW:原始套接字

protocol:附加协议,传0表示不需要其他协议,一些协议有

  • IPPROTO_TCP: TCP传输协议
  • IPPROTO_UDP: UDP传输协议
  • IPPROTO_SCTP: SCTP传输协议

connect()函数

函数原型

#include 

int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);

功能是TCP客户端建立与TCP服务器的连接
sockfd是socket()函数返回的套接字描述符
servaddr是包含要连接服务器网络信息的结构体
addrlenservaddr的大小
在调用connect前不必非得调用bind()函数,因为操作系统内核会确定源IP地址和临时端口号

该函数建立成功后会返回0, 失败返回-1。

bind()函数

函数原型

#include 
int bind(int sockfd, const struct sockaddr *myaddy, socklen_t addrlen);

功能是将客户端套接字与网络信息结构体绑定
sockfd同上,是socket()函数返回的套接字描述符
myaddr是用户网络信息结构体指针
addrlen网路信息结构体的大小

listen()函数

函数原型

#include 
int listen(int sockfd, int backlog);

sockte()函数创建套接字时,被设定为一个主动套接字,是一个将调用connect()函数发起连接请求的客户套接字。listen把一个未连接的套接字转换成一个被动套接字,指示内核应接受指向该套接字的连接请求。会使一个未连接的套接字由CLOSED状态转换成LISTEN状态。
参数:
sockfd:socked文件描述符
backlog:允许同时连接的客户端的个数,和内核为监听套接字维护的两个队列有关,两个队列如下:
未完成连接队列:服务器在三次握手中受到第一个握手信号后进入SYN——RCVD状态,为这样的套接字维护的队列
已完成连接队列:完成三次握手的套接字所维护的队列。

accept()函数

函数原型

#include 
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

服务器调用该函数,用于从已完成连接队列队头返回下一个已完成连接,如果已完成连接队列为空,则进程进入睡眠状态。
参数
sockfd:同上
cliaddr :用来返回已连接的对端(客户)的协议地址。
addrlen:addr的大小

服务器调用该函数后,可能会返回错误值或一个全新的套接字描述符,参数中的第一个参数一般称为监听套接字,调用函数后,返回一个新的套接字称为已连接套接字。系统中常常仅创建一个监听套接字进程,而当三次握手完成后,系统会为每个连接建立一个已连接套接字。

函数使用尝试

服务器端

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
	if(argc < 3)
	{
		fprintf(stderr, "Usage: %s  \n", argv[0]);
		exit(1);
	}
	int sockfd;
	struct sockaddr_in serveraddr, clientaddr;
	socklen_t addrlen = sizeof(serveraddr);
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		printf("socket error\n");
		exit(1);
	}
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(argv[2]));
	if(bind(sockfd, (struct sockaddr*)&serveraddr, addrlen) == -1)
	{
		printf("bind error\n");
		exit(1);
	}
	if(listen(sockfd, 5) == -1)
	{
		printf("listen error\n");
		exit(1);
	}
	if(accept(sockfd, (struct sockaddr*)&clientaddr, &addrlen) == -1)
	{
		printf("accept error");
		exit(1);
	}
	printf("client %s : %d connected\n",inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
	return 0;
}

客户端

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr, "usage: %s  \n", argv[0]);
        exit(1);
    }
    int sockfd;
    struct sockaddr_in serveraddr;
    socklen_t addrlen = sizeof(serveraddr);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));
    connect(sockfd, (struct sockaddr*)&serveraddr, addrlen);
    return 0;
}

客户端服务器通信相关函数

recv()/send()函数

函数原型

#include 
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

实现接收数据,返回成功接收的字节数,失败则为-1。
参数
sockfd:文件描述符,在客户端是socket()函数的返回值,在服务器是accept()的返回值
buf:保存接收到的数据
len:理论要接收的字节数
flags:标志位,0阻塞,MSG_DONTWAIT非阻塞

函数原型

#include 
ssize_t send(int sockfd, const void* buf, size_t len, int falgs)

实现发送数据,返回成功发送的字节,失败返回-1。
参数
sockfd:文件描述符,在客户端是socket()函数的返回值,在服务器是accept()的返回值
buf:要发送的数据
len:理论要发送的字节数
flags:标志位,0阻塞,MSG_DONTWAIT非阻塞

recv()和send()函数使用

服务器

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

int main(int argc, char *argv[])
{
    if(argc < 3)
    {
        printf("please input  \n");
        exit(1);
    }
    int sockfd;
    struct sockaddr_in serveraddr, clientaddr;
    socklen_t addrlen = sizeof(serveraddr);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_port = htons(atoi(argv[2]));

    bind(sockfd, (struct sockaddr*)&serveraddr, addrlen);
    listen(sockfd, 5);
    int acceptfd;
    acceptfd = accept(sockfd,(struct sockaddr*)&clientaddr, &addrlen);
    printf("client %s : %d connected\n",inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
    ssize_t bytes;
    char buf[100] = {0};
    while(1)
    {
        bytes = recv(acceptfd, buf, 100, 0);
        if(bytes == -1)
        {
            printf("recv error\n");
        }
        else if(bytes == 0)
        {
            printf("client exit\n");
            acceptfd = accept(sockfd,(struct sockaddr*)&clientaddr, &addrlen);
        }
        if(strcmp(buf, "quit") == 0)
        {
            printf("client exit\n");
            acceptfd = accept(sockfd,(struct sockaddr*)&clientaddr, &addrlen);
        }
        printf("%s-%d: %s\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), buf);
        strcat(buf, "^_^");

        if(send(acceptfd, buf, 100, 0) == -1)
        {
            printf("send error\n");
        }
    }
    return 0;
}

客户端

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    if(argc < 3)
    {
        printf("please input  \n");
        exit(1);
    }
    int sockfd;
    struct sockaddr_in serveraddr;
    socklen_t addrlen = sizeof(serveraddr);
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    connect(sockfd, (struct sockaddr*)&serveraddr, addrlen);
    char buf[100] = {0};
    while(1)
    {
        fgets(buf, 100, stdin);
        buf[strlen(buf) - 1] = '\0';

        if(send(sockfd, buf, 100, 0) == -1)
        {
            printf("send error\n");
        }

        if(strcmp(buf, "quit") == 0)
        {
            printf("client exit\n");
            exit(0);
        }

        memset(buf, 0, 100);

        if(recv(sockfd, buf, 100, 0) == -1)
        {
            printf("recv error\n");
        }

        printf("server: %s\n", buf);
    }
    return 0;
}

你可能感兴趣的:(Linux网络编程,tcp/ip,udp,网络)