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

  • Post author:
  • Post category:其他


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;

}




版权声明:本文为qq_63626307原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。