1. 程式人生 > >(一)linux C語言TCP服務端/客戶端簡單程式設計步驟

(一)linux C語言TCP服務端/客戶端簡單程式設計步驟

標頭檔案:
#ifndef _MYHEAD_H_
#define _MYHEAD_H_

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <pthread.h>
#include <semaphore.h>
#include <poll.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>


#endif


由上圖可知,TCP的服務端 5步就能完成基本功能。TCP客戶端 3步就能完成基本功能。 接下來上基本程式碼:具體函式的操作等等再講。 (為了使程式碼步驟更直觀,這裡不寫錯誤處理語句)
//TCP伺服器
#include"myhead.h"            //在linux下用man可以知道具體函式在什麼標頭檔案中,這裡用myhead.h代替
#define LISTEN_NUM 5

int main()
{
	int sockfd,new_sockfd;
	int size;

	struct sockaddr_in saddr;
	struct sockaddr_in caddr;

	size = sizeof(struct sockaddr_in);

	/*初始化sockaddr_in saddr*/
	bzero(&saddr,sizeof(saddr));   //先清零saddr
	saddr.sin_family = AF_INET;		//AF_INET表示IPv4的型別
	saddr.sin_port = htons(8888);   //繫結8888埠
	saddr.sin_addr.s_addr = htonl(INADDR_ANY);   //繫結本機埠

	sockfd = socket(AF_INET,SOCK_STREAM,0);//返回-1表示失敗;
	bind(sockfd,(struct sockaddr*)&saddr,size);//返回-1表示失敗
	listen(sockfd,LISTEN_NUM);  //返回-1表示失敗
	new_sockfd = accept(sockfd,(struct sockaddr*)&caddr,&size);//返回-1表示失敗

	write(new_sockfd,"connect sucess!",sizeof("connect sucess"));

	return 0;
}
接下來到客戶端:
//TCP客戶端
#include"myhead.h"

int main()
{
	char buf[50];
	int sockfd,size;
	struct sockaddr_in saddr;

	size = sizeof(struct sockaddr_in);

	bzero(&saddr,sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(8888); //伺服器繫結的埠
	saddr.sin_addr.s_addr = inet_addr("192.168.152.128");//伺服器的IP地址

	sockfd = socket(AF_INET,SOCK_STREAM,0); //建立一個套接字用於連線伺服器,並且這個套接字可用作對伺服器操作的檔案描述符。
											//儲存伺服器的資訊,返回-1失敗	
	connect(sockfd,(struct sockaddr*)&saddr,size);//返回-1失敗

	read(sockfd,buf,sizeof(buf));
	printf("%s\n",buf);
	return 0;
}
------------------------------------------------------------------------------------------------分割線---------------------------------------------------------------------------------------------------------------- 接下來講講可能會疑惑的地方: 1.我們看到上面程式碼的一行:bind(sockfd,(struct sockaddr*)&saddr,size);          saddr的型別明明已經定義為 sockaddr_in,為什麼在這裡又要強制轉換為sockaddr呢?          因為:sockadddr_in 其實是表明這個結構體是用於 IPv4 格式的,方便賦值。而傳出去的時候,格式就是sockaddr的,可不管你是IPv4還是IPv6的。 2.htons 和 htonl和inet_addr:         h代表主機host,n代表網路net,s程式碼短整型,htons代表把主機序換成網路序,處理短整型處理,例如埠號         htonl則是用於處理long型,一般用於IP號,但一般IP號都用 inet_addr()來傳了,唯獨htonl(INADDR_ANY),這個表示隨機選擇本機的IP         inet_addr(“IP號”)作用是把 點分十進位制數 轉換成 長整型數,點分十進位制就是 一般ip的表現形式,如192.168.1.1 ------------------------------------------------------------------------------------------------分割線---------------------------------------------------------------------------------------------------------------- 服務端各函式:      1.socket():             socket()用於建立一個socket套接字,三個引數:domain(域),type(套接字型別),protocol(協議)                 domain常用的是 AF_INET和AF_INET6對應的是IPv4,IPv6協議域。                 type 常用的是 SOCK_STREAM 和 SOCK_DGRAM 對應的是 TCP 和 UDP。                 protocol 填0即可,填0他就會自動匹配合適的協議。     2.bind():             bind()的作用是 繫結 socket套接字和初始化的結構體(如 struct sockaddr_in),三個引數:要繫結的套接字和結構體,和結構體的位元組大小                   注意:這裡需要把結構體轉換成 struct sockaddr 型別了。因為套接字繫結此結構體後是要跟外部接觸的。     3.listen():            listen()的作用是開始進行監聽,就像電話剛剛安裝好。有2個引數:分別是 伺服器的套接字,連線等待佇列的最大數目。                第一個引數好理解,那第二個引數 “連線等待佇列的最大數目”是什麼意思呢?                例如這個引數為5,並不是說這個伺服器只能被5個客戶端連線。而是服務端同一時刻能被連的只有5個客戶端。    4.accept():            accept()的作用是 開始接收客戶端的連線,如果listen像電話剛剛安裝好,那accept就是一個等待別人來電的人,當沒有人(客戶端)連上,就一直阻塞,等待。           當有人(客戶端)連上,就繼續往下執行。 客戶端:      1.socket():這個上面已經說了,這裡就不贅述了。這裡是建立一個套接字,用於連線服務端      2.connect():               作用是 把socket套接字連上服務端,若成功,操作socket套接字就等於往服務端操作,例如往socket套接字寫內容,就是往服務端寫內容。