Linux TCP通訊示例

仗劍天涯va發表於2021-01-03

TCP通訊流程

server.h

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define MAX_LINE 100
/*  用於將大寫字元轉換為小寫字元。引數為需要轉換的字串 */
void my_fun(char * p)
{
	if(p == NULL)				 /* 空串 */
		return;
	for (; *p != '\0'; p++)
		if(*p >= 'A' && *p <= 'Z') /* 判斷字元並進行轉換,也可以使用庫函式 */
			*p = *p -'A' + 'a';
}
int main(void)
{
	struct sockaddr_in sin;
	struct sockaddr_in cin;
	int l_fd;
	int c_fd;
	socklen_t len;
	char buf[MAX_LINE];					/* 儲存傳送內容的緩衝區 */
	char addr_p[INET_ADDRSTRLEN];		/* 儲存客戶端地址的緩衝區 */
	int port = 8000;					/* 埠號,使用8000 */
	int n;								/* 讀寫位元組數 */
	bzero(&sin, sizeof(sin));			/* 清空地址結構 */
	sin.sin_family = AF_INET;			/* 使用IPv4通訊域 */
	sin.sin_addr.s_addr = INADDR_ANY;	/* 伺服器可以接受任意地址 */
	sin.sin_port = htons(port);		/* 埠號轉換為網路位元組序 */
	l_fd = socket(AF_INET, SOCK_STREAM, 0); /* 創立套接字,使用TCP協議 */
	bind(l_fd, (struct sockaddr*) &sin, sizeof(sin)); /* 將地址和套接字繫結 */
	listen(l_fd, 10);						/* 開始監聽連線請求 */
	printf("waiting ...\n");
	while(1){       /* 伺服器程式多半是死迴圈 */
		            /* 接受連線請求,從此函式中返回後就可以開始通訊了 */
		c_fd = accept(l_fd, (struct sockaddr*) &cin, &len); 
		n = read(c_fd, buf, MAX_LINE);	        /* 讀取客戶端傳來的資訊 */
		inet_ntop(AF_INET, &cin.sin_addr, addr_p, sizeof(addr_p));
											/* 將客戶端地址轉換為字串 */
		printf("client IP is %s, port is %d\n", addr_p, ntohs(cin.sin_port)); 											/* 列印客戶端地址和埠號 */
		printf("content is : %s\n", buf);	/* 列印客戶端傳送過來的字串 */
		my_fun(buf);
		write(c_fd, buf, n);				/* 將轉換後的字串發給客戶端 */
		close(c_fd);			/* 通訊結束,關閉套接字,準備下一次通訊 */
	}
	if(close(l_fd) == -1){		/* 通訊結束,關閉套接字,準備下一次通訊 */
		perror("fail to close");
		exit(1);
	}
	return 0; 
}

client.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <strings.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define MAX_LINE 100
int main(int argc, char *argv[])
{
	struct sockaddr_in sin;	/* 伺服器的地址 */
	char buf[MAX_LINE];
	int sfd;
	int port = 8000;
	char *str = "test sting";	/* 預設的字串 */
	if (argc > 1) {
		str = argv[1];			/* 從命令列引數中取得使用者輸入的串 */
	}
	bzero(&sin, sizeof(sin));
	sin.sin_family = AF_INET;	/* 使用IPv4地址族 */
	/* 和本機通訊,同一臺主機擔任伺服器和客戶端的角色 */
	inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr); 
	sin.sin_port = htons(port);        /* 埠號使用8000,必須和伺服器端的一致才行 */
	sfd = socket(AF_INET, SOCK_STREAM, 0);	/* 建立套接字 */
	connect(sfd, (const struct sockaddr *)&sin, sizeof(sin));
										/* 主動連線伺服器 */
	write(sfd, str, strlen(str) + 1); /* 傳送字串,該串包含‘\0’結束符 */
	/* 讀取伺服器程式發回的串,由於是同一臺主機通訊,不存在延時的問題。
	* 但是在真正的網路環境中,要處理讀操作的延時問題。
	*/
	read(sfd, buf, MAX_LINE); 
	printf("recive from server: %s\n", buf); /* 列印該串 */
	close(sfd);								   /* 關閉套接字,結束通訊 */
	return 0;
}

makefile

all:server client

server:server.c
        gcc server.c -o server 
client:client.c
        gcc client.c -o client

clean:
        rm *.o server client

.PHONY:clean

測試

 

關於程式中用到的函式可直接在終端中使用命令:man 函式名

比如查詢socket函式用法資訊:man socket

 

相關文章