linux socket 详解
頭文件:sys/socket.h
相關結構體:
struct sockaddr
{
??? unsigned short sa_family;?? //地址族
??? char sa_data[14];?? //14字節協議地址
};
struct sockaddr_in
{
??? short int sin_family;?? //地址族
??? unsigned short int sin_port;?? //端口號
??? struct in_addr sin_addr;?? //IP地址
??? unsigned char sin_zero[8];?? //填充0以保持與struct sockaddr同樣大小
};
?
struct in_addr
?{
?? unsigned long s_addr; // that’s a 32-bit long, or 4 bytes
};
注:這兩個地址類型結構體在頭文件中定義。
相關函數:
<打開套接字>
int socket(int af,int type,int protocol);?? //返回socket套接字,在后面的調用使用它。
af指定通信發生區域(地址族)
UNIX系統有:AF_UNIX,AF_INET,AF_NS等。
DOS、WINDOWS中支持:AF_INET(網際網區域)
注:地址族與協議族相同。
type為SOCK_STREAM(建立TCP/IP連接的流式套接字)或SOCK_DGRAM(建立無連接的UDP數據報套接字)
注:進行數據報方式的數據傳輸sendto()和recvfrom()時要用SOCK_DGRAM 不然會產生錯誤。
protocol通常為0
<指定本地地址>
int bind(int sockfd,struct sockaddr *my_addr,int addrlen);
sockfd為socket返回的套接字。
my_addr指向包含本機IP地址和端口號等信息的sockaddr類型指針。
addrlen通常為sizeof(struct sockaddr)
注:定義本機地址通常為
struct sockaddr_in my_addr;
... ...
my_addr.sin_family=AF_INET;?
my_addr.sin_port=htons(指定端口號); ?? //htons()進行字節順序轉換,轉換成網絡字節優先順序。
my_addr.sin_addr.s_addr=INADDR_ANY;?? //INADDR_ANY自動獲取本機IP地址
<監聽請求>
int listen(int sockfd,int backlog);
backlog指定在請求隊列中允許的最大請求數,進入隊列的請求將等待accept()它們。
注:服務器程序的通常執行順序為 sockfd=socket( ... ... );?? bind(sockfd, ..., ...);?? listen(sockfd, ..., ...);
??? ?? 用SOCK_STREAM模式需要 accept()連接請求。
<接受連接請求>
int accept(int sockfd,struct sockaddr * ob_addr,int *addrlen);??? //返回一個新的套接字,可以通過該套接字與發出請求的客戶端進行數據傳輸。
ob_addr為一個指向sockaddr類型指針,接受請求后,客戶端的地址信息將保存在*ob_addr中。
addrlen為指向int型的指針,*addrlen值為sizeof(struct sockaddr)。
<請求連接>
int connect(int sockfd,struct sockaddr * ob_addr,int addrlen);?? //向目標地址發送連接請求。
*ob_addr為一個設置好的sockaddr類型目標地址。
注:通常
struct sockaddr_in ob_addr;
... ...
char ip[20]={"127.0.0.1"};
... ...
ob_addr.sin_family=AF_INET;
ob_addr.sin_addr.s_addr=inet_addr(ip);?? //inet_addr()函數將名為ip的字符串轉化為所需要的ip地址類型。
//相反的 inet_ntoa()函數可將這種類型轉化為字符串類型。如:cout<<inet_ntoa(ob_addr.sin_addr);
ob_addr.sin_port=htons(目標端口號);?? //必須對應服務器監聽的指定端口,bind和connect中的端點地址必須一樣,客戶端自己的端點地址中端口號設置為0,意思是讓系統自動選擇端口號。
<SOCK_STREAM模式數據傳輸>
int send(int sockfd,void * buf,int len,int flags);?? //通過sockfd套接字發送消息
sockfd為連接上的某套接字。
*buf為要傳輸的數據
len是數據長度(以字節為單位)。
flags一般為0
int recv(int sockfd,void * buf,int len,int flags);?? //通過sockfd套接字接受消息并存在*buf中
<SOCK_DGRAM模式數據傳輸>
int sendto(int sockfd,void * buf,int len,int flags,struct sockaddr * ob_addr,int addrlen);
ob_addr為sockaddr類型的指針,指向設置好的目標地址。
addrlen常為sizeof(struct sockaddr)
int recvfrom(int sockfd,void *buf, int len,int flags,struct sockaddr * ob_addr,int addrlen);
ob_addr為一個指向sockaddr類型指針,接受數據后,發送端的地址信息將保存在*ob_addr中。
<關閉套接字>
bool close(int sockfd);
注:用完了要關!
本文所用到的其他函數在netinet/in.h和arpa/inet.h中均可找到。
如果是在windows下,用VC寫socket程序,則頭文件為winsock.h。其他函數基本相同。
可以參考:
《Windows Sockets 網絡程序設計大全》蔣東興等編著 清華大學出版社
附:
//Linux 下socket通訊 服務器端設計
#include <iostream>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string>
#define ListenNum 20
#define BufLen 1024
using namespace std;
int main()
{
??? int sock,sock_new;
??? int buf_len;
??? socklen_t sin_size=sizeof(struct sockaddr);
??? int re,se;
??? char * buf_r=new char [BufLen];
??? char * buf_s=new char [BufLen];
??? struct sockaddr_in my_addr;
??? struct sockaddr_in ob_addr;
??? sock=socket(AF_INET,SOCK_STREAM,0);
??? if(sock==-1) {cout<<"socket error"<<endl;exit(0);}
??? else {cout<<sock<<endl;}
??? my_addr.sin_family=AF_INET;?
??? my_addr.sin_port=htons(3490);
??? my_addr.sin_addr.s_addr=INADDR_ANY;
??? if(bind(sock,(struct sockaddr *)& my_addr,sizeof(struct sockaddr))<0)
??? {
??? ??? cout<<"bind error"<<endl;
??? ??? exit(0);
??? }
??? cout<<"socket port: "<<ntohs(my_addr.sin_port)<<endl;
??? if(listen(sock,ListenNum)<0)
??? {
??? ??? cout<<"listen error"<<endl;
??? ??? exit(0);
??? }
???
??? while(1)
??? {
??? ??? sock_new=accept(sock,(sockaddr *)&ob_addr,&sin_size);
??? ??? if(sock_new<0)
??? ??? {
??? ??? ??? cout<<"accept error"<<endl;
??? ??? ??? exit(0);
??? ??? }
??? ??? else
??? ??? {
??? ??? ??? int p=fork();
??? ??? ??? if(p==0)
??? ??? ??? {
??? ??? ??? ??? cout<<"connect to :"<<inet_ntoa(ob_addr.sin_addr)<<" : "<<htons(ob_addr.sin_port)<<endl;
??? ??? ??? ??? int s=fork();
??? ??? ??? ??? if(s==0)
??? ??? ??? ??? {
??? ??? ??? ??? ??? do
??? ??? ??? ??? ??? {??? ??? ??? ???
??? ??? ??? ??? ??? ??? memset(buf_r,0,sizeof(buf_r));
??? ??? ??? ??? ??? ??? re=recv(sock_new,buf_r,BufLen,0);
??? ??? ??? ??? ??? ??? if(re==-1)
??? ??? ??? ??? ??? ??? {
??? ??? ??? ??? ??? ??? ??? cout<<"recv error"<<endl;
??? ??? ??? ??? ??? ??? ??? exit(0);
??? ??? ??? ??? ??? ??? }
??? ??? ??? ??? ??? ??? else if(re==0)
??? ??? ??? ??? ??? ??? {
??? ??? ??? ??? ??? ??? ??? cout<<inet_ntoa(ob_addr.sin_addr)<<"connection ended"<<endl;
??? ??? ??? ??? ??? ??? ??? close(sock_new);
??? ??? ??? ??? ??? ??? }
??? ??? ??? ??? ??? ??? else
??? ??? ??? ??? ??? ??? {
??? ??? ??? ??? ??? ??? ??? cout<<inet_ntoa(ob_addr.sin_addr)<<" -> "<<buf_r<<endl;
??? ??? ??? ??? ??? ??? }
??? ??? ??? ??? ??? }while(re>0);
??? ??? ??? ??? }
??? ??? ??? ??? else
??? ??? ??? ??? {
??? ??? ??? ??? ??? do
??? ??? ??? ??? ??? {
??? ??? ??? ??? ??? ??? memset(buf_s,0,sizeof(buf_s));
??? ??? ??? ??? ??? ??? cin.getline(buf_s,BufLen);
??? ??? ??? ??? ??? ??? se=send(sock_new,buf_s,BufLen,0);
??? ??? ??? ??? ??? ??? if(se==-1)
??? ??? ??? ??? ??? ??? {
??? ??? ??? ??? ??? ??? ??? cout<<"send error"<<endl;
??? ??? ??? ??? ??? ??? ??? exit(0);
??? ??? ??? ??? ??? ??? }
??? ??? ??? ??? ??? ??? else
??? ??? ??? ??? ??? ??? {
??? ??? ??? ??? ??? ??? ??? cout<<"sended!"<<endl;
??? ??? ??? ??? ??? ??? }
??? ??? ??? ??? ??? }while(1);
??? ??? ??? ??? }
??? ??? ??? }
??? ??? }
??? }???
??? close(sock);
??? return 0;
}
//Linux 下socket通訊 客戶端設計
#include <iostream>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#define ListenNum 20
#define BufLen 1024
using namespace std;
int main()
{
???
??? int sock,sock_new;
??? int buf_len;
??? socklen_t sin_size=sizeof(struct sockaddr);
??? char * buf_s=new char [BufLen];
??? char * buf_r=new char [BufLen];
??? char * ip=new char [20];
??? int re;
??? memset(ip,0,sizeof(ip));
??? struct sockaddr_in my_addr;
??? struct sockaddr_in ob_addr;
??? sock=socket(AF_INET,SOCK_STREAM,0);
??? if(sock==-1) {cout<<"socket error"<<endl;exit(0);}
??? else {cout<<sock<<endl;}
??? my_addr.sin_family=AF_INET;?
??? my_addr.sin_port=htons(0);
??? my_addr.sin_addr.s_addr=INADDR_ANY;
??? if(bind(sock,(struct sockaddr *)& my_addr,sin_size)<0)
??? {
??? ??? cout<<"bind error"<<endl;
??? ??? exit(0);
??? }
???
??? cout<<"socket port: "<<ntohs(my_addr.sin_port)<<endl;
??? cout<<"input ip : ";
??? cin.getline(ip,20);
???
??? ob_addr.sin_family=AF_INET;
??? ob_addr.sin_addr.s_addr=inet_addr(ip);
??? ob_addr.sin_port=htons(3490);
??? if(connect(sock,(sockaddr *)&ob_addr,sizeof(sockaddr))<0)
??? {
??? ??? cout<<"connect error"<<endl;
??? ??? exit(0);
??? }
??? else
??? {
??? ??? cout<<"connect success"<<endl;
??? ??? int p=fork();
??? ??? if(p==0)
??? ??? {
??? ??? ??? while(cin.getline(buf_s,BufLen))
??? ??? ??? {
??? ??? ??? ??? if(send(sock,buf_s,BufLen,0)!=-1)
??? ??? ??? ??? ??? cout<<"sended!"<<endl;
??? ??? ??? ??? else cout<<"send error"<<endl;
??? ??? ??? }
??? ??? }
??? ??? else
??? ??? {
??? ??? ??? do
??? ??? ??? {
??? ??? ??? ??? memset(buf_r,0,sizeof(buf_r));
??? ??? ??? ??? re=recv(sock,buf_r,BufLen,0);
??? ??? ??? ??? if(re==-1)
??? ??? ??? ??? {
??? ??? ??? ??? ??? cout<<"recv error"<<endl;
??? ??? ??? ??? ??? exit(0);
??? ??? ??? ??? }
??? ??? ??? ??? else if(re==0)
??? ??? ??? ??? {
??? ??? ??? ??? ??? cout<<inet_ntoa(ob_addr.sin_addr)<<"connection ended"<<endl;
??? ??? ??? ??? ??? close(sock);
??? ??? ??? ??? }
??? ??? ??? ??? else
??? ??? ??? ??? {
??? ??? ??? ??? ??? cout<<inet_ntoa(ob_addr.sin_addr)<<" -> "<<buf_r<<endl;
??? ??? ??? ??? }
??? ??? ??? }while(re>0);
??? ??? }
??? }
??? return 0;
}
總結
以上是生活随笔為你收集整理的linux socket 详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cisco热备份路由协议(HSRP) 2
- 下一篇: Practice:Office2010中