TCP编程步骤概述

                 刚刚接触到服务器编程的知识,来温习一下,实现最基本的TCP服务器和客户端编程流程


TCP协议是面向连接的、可靠的、字节流服务。

一、创建socket

服务器基本流程:socket、bind、listen、accept、recv/send、close

客户端基本流程:socket、connect、send/recv、close

#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain, int type, int protocol);

domain:告诉系统使用哪个底层协议族。对TCP/IP协议族而言,该参数应该设置为PF_INET(IPv4)或PF_INET6(IPv6)。对于UNIX本地域协议族而言,该参数应该设置为PF_UNIX.

type:指定服务类型。服务类型主要有SOCK_STREAM服务(流服务)和SOCK_DGRAM(数据报)服务。对于TCP/IP协议族而言,其值取SOCK_STREAM表示传输层使用TCP协议,取SOCK_DGRAM表示传输层使用UDP协议。

protocol:在前两个参数构成的协议集合下,再选择一个具体的协议。不过这个值通常都是唯一的(前两个参数通常已经确定了具体的协议)。所以几乎在所有的情况下,都把它设置为0,表示使用默认协议。

二、绑定(IP地址+端口号)

int bind(int sockfd, struct sockaddr *seraddr, int len);
struct sockaddr_in
{
    sa_family_t sin_family; //协议族
    u_int16_t sin_port; //端口号
    struct in_addr sin_addr; //IP地址
};

struct in_addr
{
    u_int32_t s_addr;
};

这里注意网络中字节序都是大端模式,一般都需要进行转化!

三、启动监听

int listen(int sockfd, int size);

size:监听队列的大小。两个队列(已完成连接的队列 + 1(正在完成连接的队列))

四、连接客户端

int accept(int sockfd, struct sockaddr *cliaddr, int *len);

返回值:返回本次连接的描述符sockfd

 

五、连接服务器

int connect(int sockfd, (struct sockaddr *)&seraddr, int len);

六、测试

服务器端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main()
{
    int sockfd = socket(PF_INET, SOCK_STREAM, 0); //创建套接字
    assert(sockfd != -1); //sockfd相当于描述符

    struct sockaddr_in ser, cli;
    memset(&ser, 0, sizeof(ser));

    ser.sin_family = PF_INET; //协议族
    ser.sin_port = htons(6000); //端口号
    ser.sin_addr.s_addr = inet_addr("127.0.0.1"); //IP地址 //回环地址
    
    int res = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser)); //绑定
    assert(res != -1);

    listen(sockfd, 5); //启动监听

    while(1)  //服务器与客户端多次通讯
    {
        int len = sizeof(cli);
        int c = accept(sockfd, (struct sockaddr *)&cli, &len); //返回本次连接到sockfd
        if(c < 0)
            continue;
        
        while(1) //接受客户端发来的数据块
        {
            char recvbuf[128] = {0};
            int n = recv(c, recvbuf, 127, 0);
            if(n <= 0)
            {
                printf("one client break!\n");
                break;
            }
            printf("%d %s\n",c, recvbuf);

            send(c, "ok", 2, 0);
        }
        close(c); //关闭当前客户端的套接字
    } //继续循环

    close(sockfd); //关闭服务器

    return 0;
}

客户端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>

int main()
{
    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    assert(sockfd != -1);

    struct sockaddr_in ser,cli;
    memset(&ser, 0, sizeof(ser));

    ser.sin_famliy = PF_INET;
    ser.sin_port = htons(6000); //端口号(与服务器匹配)
    ser.sin_addr.s_addr = inet_addr("127.0.0.1"); //回环地址

    int c = connect(sockfd, (struct sockaddr *)&ser, sizeof(ser));  //向服务器发送连接请求
    assert(c != -1);

    while(1)
    {
        char buf[128] = {0};
        fgets(buf, 128, stdin);
        buf[strlen(buf) - 1] = 0;

        send(sockfd, buf, strlen(buf), 0); //发送到服务器

        char recvbuf[128] = {0};
        recv(sockfd, recvbuf, 127, 0);
        printf("%s\n", recvbuf);

        if(strcmp(buf, "end") == 0)
            break;
    }
    close(c);

    return 0;
}

结果如下:

猜你喜欢

转载自blog.csdn.net/judgejames/article/details/84030846