Linux中socket实现TCP网络程序

之前我们讲了用socket实现UDP网络程序,这篇博客我讲一下用socket实现TCP网络程序。
首先让我们来看下面的图:
在这里插入图片描述

服务端

1.程序的第一步是创建socket套接字

#include	//头文件
//创建套接字函数,socket
int socket(int domain, int type, int protocol);
//domain:地址域,常用的有以下两种
//	AF_INET             IPv4 Internet protocols          ip(7)   
// 	AF_INET6            IPv6 Internet protocols          ipv6(7)
//type:套接字类型,常用的有以下两种
//	 SOCK_STREAM    流式套接字   
//	 SOCK_DGRAM    数据报套接字
//protocol:协议类型
//	默认为0,流式套接字默认TCP协议,数据包套接字默认UDP协议
//	在这里我们直接用UDP协议,即 IPPROTO_UDP	
//返回值:int型,成功返回套接字描述符,失败返回-1

2.程序的第二步是为套接字绑定地址信息

#include	//头文件
 int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);    
//	sockfd:套接字描述符   
//	addr:要绑定的地址信息    
//	addrlen:地址信息的长度
//	返回值:int型,成功返回0,失败返回-1

3.程序的第三步是监听,连接成功之后,获取新的socket连接

  #include <sys/types.h>          /* See NOTES */       
  #include <sys/socket.h>       
  int listen(int sockfd, int backlog);
  //	backlog:最大同时并发连接数(同一时间)

4.程序的第四步是等待客户端连接请求到达

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//  	sockfd: socket描述符
// 	 addr:  新建立连接的客户端地址信息
//  	addrlen:地址信息长度
//  返回值:返回新的socket连接描述符,失败:-1

new_sockfd 与 lst_sockfd 区别
lst_sockfd这是一个拉皮条的socket,说所有的连接请求的数据都是发送到这个socket的缓冲区,然后进行处理,会为这个新连接的客户端新建一个socket。 (这个socket接收到的数据都是连接请求)
new_sockfd这是一个干活的socket,连接建立成功之后,这个socket有自己的缓冲区往后这个客户端所发送的数据都是在这个socket的缓冲区中。
accept函数是一个阻塞型的函数,连接成功队列中如果没有新的连接,那么就会一直阻塞直到有新的客户端连接到来
5.程序的第五步是接收数据

#include		//头文件
#include
ssize_t recvfrom(int sockfd,void *buf,size_t len,int flags,struct sockaddr *src_addr,socklen_t *addrlen)
//	sockfd:套接字描述符
//	buf:用于存储接受的数据,把数据拷贝到buf当中
//	len:想要接受的数据长度
//	flags:默认为0,如果缓冲区没有数据,就阻塞等待直到有数据并拷贝完毕
//	src_addr:用于确定数据是哪一个客户端发送的,即确定发送端的地址信息
//	addrlen:发送端地址信息的长度,不能为0
//	返回值:ssize_t类型,	成功返回实际接收数据的长度,失败返回-1

6.程序的第六步是发送数据

#include<sys/types.h>	//头文件
#include<sys/socket.h>
ssize_t sendto(int sockfd,const void *buf,size_t len,int flags,const struct sockaddr *dest_addr,socklen_t addrlen);
//	sockfd:socket描述符,发送数据的时候就是通过这个socket所绑定的地址来发送
//	buf:要发送的数据
//	len:	要发送数据的长度
//	flags:0-默认阻塞式发送
//	dest_addr:数据要发送的目的地址,对端地址
//	addrlen:地址信息长度
//	返回值:ssize_t类型,返回实际发送的数据长度,失败返回-1

7.程序的第五步是关闭socket,即close(sockfd)

客户端

客户端与服务器端不同的是在创建套接字之后,会连接服务器端,这里就有一个connect函数。

int connect(int sockfd, struct sockaddr *addr,socklen_t addrlen);
//  sockfd: socket描述符
//  addr:  要连接的服务端地址
//  addrlen:   地址信息长度
//  返回值:成功:0 失败:-1

下面是源代码:
tcp_client.c

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

int main()
{    
        //1.创建套接字
        int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);    
        if(sockfd<0)
        {   
                perror("socket error");
                return -1; 
        }   
        //2.绑定:客户端程序不推荐绑定地址
        //3.向服务端发起连接请求
        struct sockaddr_in serv_addr;
        serv_addr.sin_family=AF_INET;
        serv_addr.sin_port=htons(9000);
        serv_addr.sin_addr.s_addr=inet_addr("192.168.1.101");
        //#include <sys/types.h>          /* See NOTES */
        //#include <sys/socket.h>
        //int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
        //      sockfd:套接字描述符
        //      addr:要连接的服务器地址
        //      addrlen:地址信息长度
        //      返回值:成功返回0,失败返回-1
        socklen_t len=sizeof(struct sockaddr_in);
        int ret=connect(sockfd,(struct sockaddr*)&serv_addr,len);
		if(ret<0)
        {
                perror("connect error");
                return -1;
        }
        while(1)
        {
                //4.发送数据
                char buff[1024]={0};
                scanf("%s",buff);
                send(sockfd,buff,strlen(buff),0);
                //5.接收数据
                memset(buff,0x00,1024);
                ssize_t rlen = recv(sockfd, buff, 1023, 0);
                if (rlen < 0)
                {
                        perror("recv error");
                        return -1;
                }
                else if (rlen == 0)
                {
                        printf("peer shutdown!\n");
                        return -1;
                }
                printf("server say:%s\n", buff);
        }
        close(sockfd);

        return 0;
}

tcp_server.c

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

int main()
{
        //1.创建套接字socket
        int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(sockfd<0)
        {   
                perror("socket error");
                return -1; 
        }   
        //2.为socket绑定地址信息
        struct sockaddr_in addr;
        addr.sin_family=AF_INET;
        addr.sin_port=htons(9000);
        addr.sin_addr.s_addr=inet_addr("192.168.1.101");
        socklen_t len=sizeof(struct sockaddr_in);
        int ret=bind(sockfd,(struct sockaddr *)&addr,len);
        if(ret<0)
        {    
                perror("bind error");
                return -1; 
        }   
		//3. 监听
        //  int listen(int sockfd, int backlog);
        //  sockfd:     socket描述符
        //  backlog:   最大的同时并发连接数
        if(listen(sockfd,5)<0)
        {
                perror("listen error");
                return -1;
        }
        //4.获取连接成功的socket
        while(1)
        {
                int new_sockfd;
                struct sockaddr_in cli_addr;
                len=sizeof(struct sockaddr_in);
                //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
                //  sockfd: socket描述符
                //  addr:  新建立连接的客户端地址信息
                //  addrlen:地址信息长度
                //  返回值:返回新的socket连接描述符,失败:-1
                new_sockfd=accept(sockfd,(struct sockaddr *)&cli_addr,&len);
                if(new_sockfd<0)
                {
                        perror("accept error");
                        continue;
                }
                printf("new conn %s:%d\n", inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));
                while(1)
                {
                        //5.接收数据
						char buff[1024]={0};
                        ssize_t rlen=recv(new_sockfd,buff,1023,0);
                        if(rlen<0)
                        {
                                perror("recv error");
                                close(new_sockfd);
                                continue;
                        }else if(rlen ==0)
                                {
                                        perror("peer shutdown\n");
                                        close(new_sockfd);
                                        continue;
                                }
                        printf("client[%s:%d] say:%s\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port), buff);
                        //6.发送数据
                        memset(buff, 0x00, 1024);
                        scanf("%s", buff);
                        send(new_sockfd, buff, strlen(buff), 0);
                }
        }
        close(sockfd);
        return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值