网络通信Socket搭建tcp服务端

网络通信Socket搭建tcp服务端

1.tcp概念

	TCP即传输控制协议,是一种面向连接的、可靠的、基于字节流的通信协议。每发出一个数据包都要求确认,如果有一个数据包丢失,就收不到确认,发送方就必须重发这个数据包。为了保证传输的可靠性,TCP协议在UDP基础之上建立了三次对话的确认机制,即在正式收发数据前,必须和对方建立可靠的连接。TCP数据包由首部和数据两部分组成,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的长度,以确保单个TCP数据包不必再分割。 
传输层的主要工作是定义端口,标识应用程序身份,实现端口到端口的通信,TCP协议可以保证数据传输的可靠性.

2.socket套接字概念

socket的使用场景以及分类

socket本来也是用于本地进程间通信的,后来有了TCP/IP协议簇的加入,才能实现跨主机通信。

socket是一个函数,我们可以指定参数告诉内核封装什么样的协议。socket是一种特殊的文件描述符 (everything in Unix is a file)并不仅限于TCP/IP协议,其他体系结构也会用到 socket。

套接字分为:

流式套接字(SOCK_STREAM):

TCP提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。

数据报套接字(SOCK_DGRAM)UDP:

提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。

原始套接字(SOCK_RAW)

可以对较低层次协议如IP、ICMP直接访问

1.创建套接字

#include <sys/socket.h>   
int socket(int domain, int type, int proto-col);
domain :
	通信方式,协议簇:
        Name         Purpose                                    Man page
       AF_UNIX      Local communication                        unix(7)
       AF_LOCAL     Synonym for AF_UNIX
       AF_INET      IPv4 Internet protocols                    ip(7)
       AF_AX25      Amateur radio AX.25 protocol               ax25(4)
       AF_IPX       IPX - Novell protocols
       AF_APPLETALK AppleTalk                                  ddp(7)
       AF_X25       ITU-T X.25 / ISO-8208 protocol             x25(7)
       AF_INET6     IPv6 Internet protocols                    ipv6(7)
       AF_DECnet    DECet protocol sockets
       AF_KEY       Key management protocol, original
type:
	传输模型
        tcp:SOCK_STREAM
        udp:SOCK_DGRAM
proto-col:
	额外协议
        ipv4协议 为0

2.绑定套接字

2.1转换端口

#include <arpa/inet.h>
       uint16_t htons(uint16_t hostshort);
功能:
	主机字节序转换成网络字节序(一般都是小端转大端)
返回值:
	成功返回转换过后的数值
参数列表:
	hostshort:要转换的值,只能两个字节

2.2转换IP

方式一:
int inet_aton(const char *cp, struct in_addr *inp);
功能:
	把字符串格式转换成网络字节序的二进制格式
返回值:
	成功返回1,失败返回0
参数列表:
	cp:字符串
	inp:存放转换后的数值
方式二:
in_addr_t inet_addr(const char *cp);
功能:
	把字符串格式转换成网络字节序的二进制格式
返回值:
	返回转换成功后的二进制
参数列表:
	cp:字符串
方式三:
    IP地址直接设置为INADDR_ANY
    INADDR_ANY是一个常量,它指代的是一个特殊的IP地址,即0.0.0.0。在网络编程中,当一个进程需要绑定一个网络端口时,可以使用INADDR_ANY来指定该端口可以接受来自任何IP地址的连接请求。
	具体来说,当一个进程需要监听某个网络端口时,需要调用bind()函数将该端口与一个IP地址绑定。如果使用INADDR_ANY作为IP地址参数,就表示该端口可以接受来自任何IP地址的连接请求。这样,无论是本地主机还是远程主机,只要它们能够访问该端口,就可以与该进程建立连接。

2.3绑定套接字

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
int sockfd:
	套接字
onst struct sockaddr *addr:
    ip地址和端口信息(里面存放字符串和整数,所以需要类型转换) man 7 ip查看
     struct sockaddr {
         		//协议簇
               sa_family_t sa_family;
               char        sa_data[14];
           }
         struct sockaddr_in {
               sa_family_t    sin_family; /* address family: AF_INET */
               in_port_t      sin_port;   /* port in network byte order */
               struct in_addr sin_addr;   /* internet address */
           };
			* Internet address. */
           struct in_addr {
                 /* address in network byte order */
               uint32_t       s_addr;   
           };


    ip地址端口信息
socklen_t addrlen:
	结构体大小

3.监听socket

int listen(int sockfd, int backlog);
功能:
	规定监听队列的大小
返回值:
	成功返回0,失败返回-1
参数:
int backlog:
	规定大小,队列大小为2*backlog+1

4.接收连接请求

从已决队列中拿出一个完成三次握手的连接请求

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:
	从已决队列中拿出一个完成三次握手的连接请求,没有请求就阻塞等待
返回值:
	成功返回一个新的用于通信的套接字,失败返回-1
参数列表:
	sockfd:基础套接字
	addr:用于存放客户端信息
	addrlen:结构体大小,不能&sizeof()

5.拿到客户端ip/port号

int inet_aton(const char *cp, struct in_addr *inp);
功能:
    把ip地址转化为用于网络传输的二进制数值
返回值:
    地址
    char *ip=inet_ntoa(clt.sin_addr);
    int port=ntohs(clt.sin_port);

6.接收客户端消息

//收消息
1. ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    int sockfd

​ 该参数指明从文件描述符fd的缓冲区读取数据。

    void *buf

​ recv()函数簇读到的数据将保存到buf所指向的空间中,用法和read()同理。

    size_t len

​ 该参数指明本次调用接收数据的最大长度。

    int flags

​ 如果flags设置为0,那么recv()函数和read()没有任何区别。flags还可以通过OR设置如下参数:

10.源码

/*===============================================
*   文件名称:tcpSever.c
*   创 建 者:     
*   创建日期:2024年01月02日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define SEVER_PORT 8080
#define SEVER_IP "192.168.2.138"
int main(int argc, char *argv[])
{ 
    //1.创建套接字(ipv4协议)
    int sfd=socket(AF_INET,SOCK_STREAM,0);
    if(sfd<0){
        perror("sfd");
        return-1;
    }
    printf("创建成功\n");
    printf("%d\n",sfd);
    //解决端口占用
    int optval=1;
    setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));
    int ret=0;
    char buf[1024];
    //2.绑定套接字
    struct sockaddr_in ser;
    ser.sin_family=AF_INET;
    //格式化端口
    ser.sin_port=htons(SEVER_PORT);
    //格式化ip
    ser.sin_addr.s_addr=inet_addr(SEVER_IP);
    //3.绑定socket
    ret=bind(sfd,(struct sockaddr*)&ser,sizeof(ser));
    if(ret<0){
        perror("bind");
        return-1;
    }
    printf("绑定成功\n");
    //4.监听套接字
    ret=listen(sfd,5);
    if(ret<0){
        perror("listen");
        return-1;
    }
    printf("监听成功\n");
    printf("%s %hu\n",SEVER_IP,SEVER_PORT);
    //5.阻塞连接
    struct sockaddr_in clt;
    int len=sizeof(struct sockaddr_in);
    //6.返回客户端描述符套接字
    int cfd=accept(sfd,(struct sockaddr *)&clt,&len);
    printf("%d\n",cfd);
    //7.拿到客户端的IP和端口号
    char *ip=inet_ntoa(clt.sin_addr);
    int port=ntohs(clt.sin_port);
    printf("客户端ip: %s 端口号: %d\n",ip,port);
    //8.接收数据
    while(1){
        //清空缓冲区
        bzero(buf,sizeof(buf));
        //收消息
        ret=recv(cfd,buf,sizeof(buf),0);
        if(ret==0){
            perror("recv");
            return-1;
        }
        printf("收到数据: %s 大小为: %d\n",buf,ret);
        //主动退出
        if(!strcmp(buf,"exit")){
            break;
        }
    }
    //9.关闭套接字
    close(sfd);
    close(cfd);
    return 0;
} 


网络通信搭建tcp客户端

1.创建套接字

2.创建连接

3.发送数据

源码

/*===============================================
*   文件名称:tcpClient.c
*   创 建 者:     
*   创建日期:2024年01月02日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define SEVER_PORT 8080
#define SEVER_IP "192.168.2.138"
int main(int argc, char **argv)
{ 
    //1.创建套接字(ipv4协议)
    int sfd=socket(AF_INET,SOCK_STREAM,0);
    if(sfd<0){
        perror("sfd");
        return-1;
    }
    printf("创建成功\n");
    printf("%d\n",sfd);
    int ret=0;
    char buf[1024]={0};
    struct sockaddr_in ser;
    ser.sin_family=AF_INET;
    //格式化端口
    ser.sin_port=htons(SEVER_PORT);
    ser.sin_addr.s_addr=inet_addr(SEVER_IP);
    //3.创建连接
    ret=connect(sfd,(struct sockaddr*)&ser,sizeof(ser));
    if(ret<0){
        perror("connect");
        return-1;
    }
    printf("连接成功\n");
    printf("%s %hu\n",SEVER_IP,SEVER_PORT);
    //4.发送数据
    while(1){
        //清空缓冲区
        bzero(buf,sizeof(buf));
        //发送消息
        scanf("%s",buf);
        //发消息
        ret=send(sfd,buf,sizeof(buf),0);
        if(ret==-1){
            perror("send");
            return-1;
        }
        printf("发送数据:%d\n",ret);
        //主动退出
        if(!strcmp(buf,"exit")){
            break;
        }
    }
    //5.关闭套接字
    close(sfd);
    return 0;
} 
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值