基於c語言的TCP客戶端、服務端基礎程式碼

周半仙發表於2024-06-05

基於c語言的TCP客戶端、服務端基礎程式碼

基本流程:

image

  1. 客戶端:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
*   tcp客戶端(傳送)
*
*
*
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main(int argc, char *argv[])
{
    // 檢查引數有效性
    if (argc != 3)
    {
        fprintf(stderr, "argument is invaild ,errno:%d,%s\n", errno, strerror(errno));
        exit(1);
    }

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;             // 協議族,是固定的
    addr.sin_port = htons(atoi(argv[1]));  // 伺服器埠,必須轉換為網路位元組序
    addr.sin_addr.s_addr = inet_addr(argv[2]); // 伺服器地址 "192.168.64.xxx"

    connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));

    char sendbuff[100];
    char recvbuff[100];

    while (1)
    {
        bzero(sendbuff, 100);
        scanf("%s",sendbuff);
        // fgets(sendbuff, 100, stdin);

        // 向服務端傳送資料
        write(sockfd, sendbuff, strlen(sendbuff));

        // 接收TCP回彈伺服器的訊息
        
        printf("收到訊息recvbuff = %s\n", recvbuff);
        bzero(recvbuff, 100);
    }
    close(sockfd);
    return 0;
}
  1. 服務端:


#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
 #include <unistd.h>
//TCP伺服器程式碼   ./xxx   port

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
*   tcp服務端(接收)
*
*
*
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main(int argc, char const *argv[])
{
	//1.建立TCP套接字
	int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (tcp_socket == -1)
	{
		fprintf(stderr, "tcp socket error,errno:%d,%s\n",errno,strerror(errno));
		exit(1);
	}

	//2.繫結自身的IP地址和埠
	struct sockaddr_in  host_addr;

	host_addr.sin_family 		= AF_INET; 						//協議族,是固定的
	host_addr.sin_port   		= htons(atoi(argv[1]));			//目標埠,必須轉換為網路位元組序
	host_addr.sin_addr.s_addr   = htonl(INADDR_ANY);		    //目標地址  INADDR_ANY 這個宏是一個整數,所以需要使用htonl轉換為網路位元組序

	bind(tcp_socket,(struct sockaddr *)&host_addr, sizeof(host_addr));

	//3.設定監聽  佇列最大容量是5
	listen(tcp_socket,5);

	//4.等待接受客戶端的連線請求
	struct sockaddr_in  client;
	socklen_t client_len = sizeof(client);

	int connect_fd = accept(tcp_socket,(struct sockaddr *)&client,&client_len); //會阻塞
	char buf[128] = {0};

	//5.說明雙方建立連線,此時可以接收資料
	while(1)
	{
		
		
		read(connect_fd,buf,sizeof(buf));
		printf("recv from [%s],data is = %s\n", inet_ntoa(client.sin_addr) ,buf);
		bzero(buf,sizeof(buf));
	}


	return 0;
}
  1. 三次握手示意圖:
    image

  2. 示意圖解釋:

第一次握手:傳送一個SYN標記(請求同步標記)

​ 傳送一個序列號seq:x

第二次握手:返回一個SYN標記

​ 返回一個ACK(應答標記,表示我知道了)

​ 返回一個序列號seq:y

​ 返回一個x+1序列號ack(告訴客戶端希望下一次資料從+1開始)

第三次握手:傳送一個ACK標記

​ 傳送一個序列號seq:x+1

​ 傳送一個序列號ack:y+1

相關文章