目錄
1.ip:埠 TCP/IP協議
2.socket 頭檔案 sys/socket.h
3.位元組序
4.ip地址轉換函式
5.sockaddr和sockaddr_in
6.服務器端基本函式 bind listen accept
7.客戶端基本函式 connect
8.send 和 recv
8.多執行緒
9.通信流程
10.多執行緒并發樣例程式
1.ip:埠 TCP/IP協議
AF_INET IPv4
AF_INET6 IPv6SOCK_STREAM tcp協議
2.socket 頭檔案 sys/socket.h
套接字對應程式猿來說就是一套網路通信的介面,使用這套介面就可以完成網路通信,
網路通信的主體主要分為兩部分:客戶端和服務器端
int socket(int domain, int type, int protocol);
(1)在引數表中,domain指定使用何種的地址型別,比較常用的有:
PF_INET, AF_INET: Ipv4網路協議;
PF_INET6, AF_INET6: Ipv6網路協議,
(2)type引數的作用是設定通信的協議型別,可能的取值如下所示:
SOCK_STREAM: 提供面向連接的穩定資料傳輸,即TCP協議,
(3)一般取0即可
3.位元組序
ittle-Endian -> 主機位元組序 (小端)
Big-Endian -> 網路位元組序 (大端)
頭檔案:#include <arpa/inet.h> //包含 sys/socket.h
uint16_htons(uint16_t hostshort) //短整形 主機位元組序 --> 網路位元組序
uint32_htonl(uint32_t hostlong) //長整形 主機位元組序 -->網路位元組序uint16_ntohs(uint16_t netshort) //短整形 網路位元組序 -->主機位元組序
uint32_ntohl(uint32_t netlong) //長整形 網路位元組序 -->主機位元組序
4.ip地址轉換函式
int inet_pton(int af,const char *src,void *dst) //主機ip地址 -->網路ip位元組序
注: 主機ip地址是字串 、網路ip位元組序是整形
(1) af : IP協議 AF_INET、AF_INET6
(2) src: 傳入引數 十進制的ip地址
(3) dst:大整形ip 存入地址//網路ip位元組序 --> 主機ip地址
const char* inet_ntop(int af,const void *src,char *dst,socklen_t size)
回傳值:成功回傳指向 dst的指標 失敗回傳空指標與此相關只能轉換AF_INET ip位元組序的函式
inet_addr IP地址的字串賦值轉換為in_addr型別
inet_ntoa,可以把一個in_addr型別轉換為一個字串,
5.sockaddr和sockaddr_in
sockaddr
頭檔案#include <sys/socket.h>中定義
sockaddr的缺點:sa_data把目標地址和埠存在一起
struct sockaddr {
sa_family_t sin_family;//地址族
char sa_data[14]; //前2位元組:埠 后4位元組:ip地址 后8位元組作為填充
};
sockaddr_in
struct sockaddr_in{
short sin_family;//(地址族)
unsigned short sin_port;/*埠號*/
struct in_addr sin_addr;/*IP 地址*/
unsigned char sin_zero[8];/*Same size as struct sockaddr沒有實際意義,只是為了 跟SOCKADDR結構在記憶體中對齊*/
};
我的理解:網路通信api的引數默認為sockaddr,但由于不好指定埠和ip地址,一般定義sockaddr_in 來方便賦值埠和ip地址,呼叫api函式時強轉為sockaddr型別即可
6. 服務器端基本函式 bind listen accept
intbind(intsockfd ,conststructsockaddr * my_addr, socklen_t addrlen);
int listen(int fd, int backlog)
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
7. 客戶端基本函式 connect
intconnect(intsock,structsockaddr *serv_addr, socklen_t addrlen)
8.send 和 recv
int send( SOCKET s, const char *buf, int len, int flags );
int recv( SOCKET s, const char *buf, int len, int flags);
8.多執行緒
頭檔案 pthread.h
創建執行緒 pthread_create (與windows CreateThread 用法相似)
intpthread_create(pthread_t *tidp,constpthread_attr_t *attr,void*(*start_rtn)(void*),void*arg);
pthread_detach()與pthread_join
pthread_detach()即主執行緒與子執行緒分離,子執行緒結束后,資源自動回收,
pthread_join()即是子執行緒合入主執行緒,主執行緒阻塞等待子執行緒結束,然后回收子執行緒資源,
int pthread_join(pthread_t tid); 若成功則回傳0,若出錯則為非零,
int pthread_join(pthread_t tid); 若成功則回傳0,若出錯則為非零,
9.通信流程

10.多執行緒并發樣例程式
服務器端
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<pthread.h>
void * working(void *arg);
struct SockInfo
{
struct sockaddr_in addr;
int fd;
};
struct SockInfo infos[512];
int main()
{
//1.創建監聽的套接字
int fd = socket(AF_INET,SOCK_STREAM,0);
if(fd==-1)
{
perror("socket");
return -1;
}
//2.連接本地的ip 埠
struct sockaddr_in saddr;
saddr.sin_family =AF_INET;
saddr.sin_port = htons(9999);
saddr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(fd,(struct sockaddr*) &saddr,sizeof(saddr));
if(ret==-1)
{
perror("bind");
return -1;
}
//3.設定監聽
ret = listen(fd,128);
if(ret==-1)
{
perror("listen");
return -1;
}
//初始化客戶端陣列
int max = sizeof(infos)/sizeof(infos[0]);
for(int i=0; i<max;i++)
{
bzero(&infos[i],sizeof(infos[i]));
infos[i].fd=-1;
}
//4.阻塞并等待客戶端的連接
while(1)
{
struct SockInfo * pinfo;
int addrlen =sizeof(sockaddr_in);
for(int i=0; i<max;i++)
{
if(infos[i].fd==-1)
{
pinfo=&infos[i];
break;
}
}
int cfd= accept(fd,(struct sockaddr*) &pinfo->addr,&addrlen);
if(cfd==-1)
{
perror("accept");
continue;
}
pinfo->fd=cfd;
//創建子執行緒
pthread_t tid;
pthread_create(&tid,NULL,working,pinfo);
phread_detach(tid);
}
close(fd);
return 0;
}
void working(void *arg)
{
//5.連接成功列印客戶端資訊
struct SockInfo *pinfo = (struct SockInfo*) arg;
char ip[32];
printf("客戶端ip: %s, 埠: %d\n",
inet_ntop(AF_INET,&pinfo->addr.sin_addr.s_addr,ip,sizeof(ip)),
ntohs(&pinfo->addr.sin_port));
while(1)
{
//接受資料
char buf[1024];
int len =recv(pinfo->fd,buf,sizeof(buf),0);
if(len>0)
{
printf("client say: %s",buf);
send(pinfo->fd,buf,sizeof(buf),0);
}
else if(len==0)
{
printf("clinet closed!\n");
break;
}else
{
perror("recv");
break;
}
}
//關閉socket
close(pinfo->fd);
return NULL;
}
客戶端
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
int main()
{
//1.創建通信的套接字
int fd = socket(AF_INET,SOCK_STREAM,0);
if(fd==-1)
{
perror("socket");
return -1;
}
//2.連接服務器的ip 埠
struct sockaddr_in saddr;
saddr.sin_family =AF_INET;
saddr.sin_port = htons(9999);
inet_pton(AF_INET,"121.41.88.239",&saddr.sin_addr.s_addr);
int ret = connect(fd,(struct sockaddr*) &saddr,sizeof(saddr));
if(ret==-1)
{
perror("connect");
return -1;
}
int number=0;
while(1)
{
//接受資料
char buff[1024];
sprintf(buff,"hello %d\n ",number++);
send(fd,buff,strlen(buff)+1,0);
memset(buff,0,sizeof buff);
int len=recv(fd,buff,sizeof(buff),0);
if(len>0)
{
printf("server say: %s\n",buff);
}else if(len==0)
{
printf("server closed!\n");
break;
}else
{
perror("recv");
break;
}
sleep(1);
}
//關閉socket
close(fd);
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/350947.html
標籤:其他
