网络编程:TCP客户端的搭建流程(附源码)

TCP客户端的搭建流程:

1.创建套接字  socket

2.要指定服务器的ip和端口、协议等

绑定ip 和端口号  bind(可以不绑定)

3.连接服务器 connect

4.通信        

    1. read、write
    2. Recv、send
    3. Recvfrom、sendto

5.关闭套接字:close/shutdown(套接字,howto):howto:0(读端) 1(写端)

出现问题如何优化:

1、

  1. 设置套接字重用:setsockopt()
    1. Int opt = 1;
    2. Setsockopt(套接字,SOL_SOCKET,  SO_REUSEADDR, &opt, sizeof(opt) );
  2. 打印客户端ip和端口
    1. 需要创建新的结构体变量保存 客户端的ip等信息
    2. Eg:
      • struct sockaddr_in caddr ={0};
      • int len = sizeof(caddr);
      • Accept(listenfd, (struct sockaddr *)caddr,  &len);
      • Printf(“ip:%s--port:%d\n”, inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));

代码如下:

#include <stdio.h>
#include <string.h>

 #include <sys/types.h>          /* See NOTES */  //man  socket
 #include <sys/socket.h>

 #include <sys/socket.h>    //  man 7 ip
 #include <netinet/in.h>
 #include <netinet/ip.h> /* superset of previous */

#include <sys/socket.h>  //man 3 inet_addr  
#include <netinet/in.h>
#include <arpa/inet.h>  //man 2 read 
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>

#define SIZE 1024
#define SERV_IP "0"
#define SERV_PORT 6666

int main(int argc,const char *argv[])
{
    int listenfd;  //用于保存监听套结字
    int connfd  ; //用于通信的套结字
    int ret; 
    char recvbuf[SIZE] = {0}; 

    //1、创建套结字 socket 
    listenfd = socket(AF_INET, SOCK_STREAM, 0); //AF_INET:IPV4协议  SOCK_STREAM:流式套结字
    if(-1 == listenfd)
    {
        perror("socket");
        return -1;
    }
    printf("socket %d ok\n", listenfd); //
    //填充ip等信息到通用ip结构体
    #if 0
    struct sockaddr_in saddr ;
    memset(&saddr, 0, sizeof(saddr)); // bzero(&saddr, sizeof(saddr));
    saddr.sin_family     = AF_INET;   //IPV4 协议
    saddr.sin_port       =  htons(6666);//端口号 :1024-49151
    saddr.sin_addr.s_addr=   inet_addr("192.168.16.100"); 
    #else
    struct sockaddr_in saddr = { 
        .sin_family = AF_INET, 
        .sin_port = htons(SERV_PORT), 
        .sin_addr.s_addr = inet_addr(SERV_IP)   
    }; 
    #endif
    //优化2:设置套结字属性  端口重用  setsockopt(); 
    int opt = 1; 
    setsockopt(listenfd, SOL_SOCKET,  SO_REUSEADDR, &opt, sizeof(opt)); 
    //2、绑定ip和端口a
    socklen_t  slen = sizeof(saddr); 
    ret =  bind(listenfd,  (struct sockaddr* )&saddr, slen); 
    if(-1 == ret)
    {
        perror("bind");
        return -1;
    }
    printf("bind ok\n");
    //3、监听
    ret = listen(listenfd, 8); 
    if(-1 == ret)
    {
        perror("listen");
        return -1;
    }
    printf("listen ok, wait for connect...\n");

    //优化1:循环监听客户端 
    while(1)
    {
        //4、处理客户端请求
    #if 0
        //accept之后 监听套结字listenfd  转接 为新的 通信套结字 connfd 使用
            connfd = accept(listenfd, NULL, NULL); //不关心客户端的ip和端口
            printf("had   client connect%d\n", connfd); 
    #else
        //优化 3:关心客户端ip和端口了并打印
        struct sockaddr_in caddr = {0};
       // memset(caddr, 0, sizeof(caddr)); 
        socklen_t clen = sizeof(caddr); 
        connfd = accept(listenfd, (struct sockaddr *)&caddr, &clen); 
        if(connfd == -1)
        {
            perror("accept");
            return -1;
        }

        printf("client(%s:%d) had connected success\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port) );  


    #endif 
        //5、通信
        while(1)
        {
            memset(recvbuf, 0, sizeof(recvbuf));
            int count = read(connfd, recvbuf, sizeof(recvbuf));
            if(-1 == count)
            {
                perror("read");
                return -1;
            }
            else if(0 == count)
            {
                printf("client quit\n");
                break; 
            }
            printf("recv:%s\n",recvbuf); 

            //判断客户端发来的指令  做出响应
            if( 0 == strncmp(recvbuf, "sl", 2) )
            {
                system("sl");
            }
            else if(0 == strncmp(recvbuf, "xcowsay", 7))
            {
                system("xcowsay   爱 老虎油!");
            }
            //

            int i;
            for(i=0; i<count; i++)
            {
                recvbuf[i] =  toupper(recvbuf[i]);  //将单个字符转化大写
            }

            //write(connfd, "ok", 2);
            write(connfd, recvbuf, count); 
        }
        //6、关闭套结字退出
        close(connfd);
    }
close(listenfd);
return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

এ᭄星辰

混口饭吃。。。。。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值