1. 程式人生 > >Linux-TCP/IP socket程式設計

Linux-TCP/IP socket程式設計

伺服器

    1、建立連線
    socket(),分配檔案描述符,即監聽套接字
    bind(),將套接字與本地IP地址和埠繫結
    listen(),監聽特定埠,可設定監聽連線最大個數
    accept(),阻塞等待客戶端連線
    2、資料收發
    read()/recv()阻塞等待客戶端傳送資料,收到資料後從read()/recv()返回資料和資料數量
    write()/send()將處理結果傳送給客戶端,然後繼續呼叫read()/recv()等待客戶端請求
    3、關閉連線
    當read()/recv()返回0的時候,說明客戶端發來FIN資料包,即關閉連線,呼叫close()關閉連線套接字和監聽套接字
    當客戶端呼叫close()關閉連線套接字時也會受到客戶端發開的斷開連線請求

客戶端

    1、建立連線
    socket(),分配檔案描述符
    connect(),向伺服器傳送建立連線請求
    2、資料收發
    write()/send(),將資料傳送給伺服器
    read()/recv(),阻塞等待伺服器應答回覆資料
    3、關閉連線
    當沒有資料傳送的時候,呼叫close()關閉連線套接字,即關閉連線,向伺服器傳送FIN資料報
    或者write()/send()傳送0位元組給伺服器表示斷開連線

TCP通訊過程

    圖片轉載自:https://blog.csdn.net/upupday19/article/details/78916142

示例程式碼

    標頭檔案:std.h

#ifndef _STD_
#define _STD_

// 標頭檔案 //
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <grp.h>
#include <string.h>
#include <time.h>
#include <string.h>
#include <errno.h>
//tcp//
#include <sys/types.h>  
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> 
#include <arpa/inet.h>

//錯誤提示//
#define err_exit(function)					\
		do {								\
			fprintf(stderr, "in %s at %s %d:\n%s : %s\n", __FUNCTION__, __FILE__, __LINE__ - 1, function, strerror(errno)); \
			exit(EXIT_FAILURE);				\
		} while(0)

#endif

    伺服器程式碼:test_tcp_server.c

//伺服器端//
#include "std.h"

int main(void)
{
	//定義伺服器監聽套接字和連線套接字
	int listenfd = -1;
	int connfd = -1;
	struct sockaddr_in server, client;//定義伺服器對應的套接字地址
	char buf[BUFSIZ];
	int ret=-1;

	//初始化套接字地址結構體
	memset(&server, 0, sizeof(server));
	server.sin_family = AF_INET;//IPv4
	server.sin_port = htons(888);//設定監聽埠
	//server.sin_addr.s_addr = inet_addr("192.168.1.50");//誰的地址?
	//server.sin_addr.s_addr = inet_addr("0");//?
	//server.sin_addr.s_addr = INADDR_ANY;//?
	server.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY接收任意IP的連線請求
	
	//建立套接字
	if (0 > (listenfd = socket(AF_INET, SOCK_STREAM, 0)))
		err_exit("socket");

	//繫結套接字和本地IP地址和埠
	if (0 > bind(listenfd, (struct sockaddr *)&server, sizeof(server)))
		err_exit("bind");

	//設定listen_fd為監聽描述符
	listen(listenfd, 1024);//1024為最大連線個數
	printf("listen...\n");

	//accept阻塞等待客戶端請求
	memset(&client, 0, sizeof(client));
	socklen_t len = sizeof(client);
	if (0 > (connfd = accept(listenfd, (struct sockaddr *)&client, &len)))
		err_exit("accept");
	printf("client's ip is: %s, port is: %d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
	fflush(stdout);

	while(1)
	{
		//讀取客戶端發來的資訊
		memset(buf, 0, sizeof(buf));
		if (0 > (ret = recv(connfd, buf, BUFSIZ, 0)))
			err_exit("recv");
		else if (0 == ret)//客戶端關閉連線請求斷開或傳送0位元組資料會走這裡
		{
			printf("client quit!\n");
			//關閉連線套接字
			close(connfd);
			//關閉監聽套接字
			close(listenfd);
			exit(0);
		}
		buf[ret] = '\0';
		printf("recv client: %s\n", buf);
		//向客戶端傳送資訊
		send(connfd, "ok", sizeof("ok"), 0);		
	}
}

    客戶端程式碼:test_tcp_client.c

//客戶端//
#include "std.h"

int main(void)
{
	int connfd = -1;//定義客戶端套接字
	struct sockaddr_in server;//定義伺服器的套接字地址
	char buf[BUFSIZ];//stdlib.h定義BUFSIZ=8192
	int ret=-1;

	//初始化伺服器套接字地址
	memset(&server, 0, sizeof(server));
	server.sin_family = AF_INET;//IPv4
	server.sin_port = htons(888);//伺服器埠
	server.sin_addr.s_addr = inet_addr("192.168.1.50");//伺服器IP地址

	//建立套接字
	if (0 > (connfd = socket(AF_INET, SOCK_STREAM, 0)))
		err_exit("socket");

	//傳送連線請求
	if (0 > connect(connfd, (struct sockaddr *)&server, sizeof(server)))
		err_exit("connect");
	printf("connect success!\n");
	
	//輸入並向伺服器傳送字串
	memset(buf, 0, sizeof(buf));
	fgets(buf, sizeof(buf), stdin);
	send(connfd, buf, strlen(buf)-1, 0);//-1目的是去除\n字元

	//從伺服器接收資料
	if (0 > (ret = recv(connfd, buf, BUFSIZ, 0)))
		err_exit("recv");
	else if (0 == ret) {
		printf("server quit!\n");
		close(connfd);
	}
	buf[ret] = '\0';
	printf("recv server: %s\n", buf);

	//memset(buf, 0, sizeof(buf));
	fgets(buf, sizeof(buf), stdin);
	send(connfd, buf, strlen(buf)-1, 0);

	close(connfd);
	exit(0);
}

擴充套件

    select,poll,epoll實現機制區別:https://www.cnblogs.com/aspirant/p/9166944.html