网络编程(套接字)

时间:2022-01-25 00:03:27
网络编程
1.套接字的类型
1.1流式套接字SOCK_STREAM
提供面向连接、可靠的数据传输服务,数据无差错、无重复的发送,且按发送顺序接收。实际上它是基于TCP协议实现的。
1.2数据报套接字SOCK_DGRAM
提供无连接服务。数据包以独立包形式发送,不提供无措保证,数据可能丢失或重复,并且接收顺序混乱。数据报式套接字实际上是基于UDP协议实现的。
1.3原始套接字SOCK_RAW


2.基于TCP的socket编程
服务器器段流程:
1)创建套接字(socket)
2)将套接字绑定到本地地址和端口上(bind)
3)将套接字设为监听模式,准备接收客户请求(listen)
4)等待客户请求到来;当请求到来后,接收连接请求,返回一个新的对应于此次连接的套接字(accept)
5)用返回的套接字和客户端进行通信(send/recv)
6)返回,等待另一客户请求
7)关闭套接字
基于TCP的socket编程
1)创建套接字(socket)
2)向服务器发出连接请求(connect)
3)和服务器段进行通信(send/recv)
4)关闭套接字
在服务器端,当调用accept函数时,程序就会等待,等待客户端调用connect函数发出连接请求,然后服务器接收请求,于是双方就建立了连接。之后,服务器端和客户端就可以利用send和recv函数进行通信了。在客户端并不需要调用bind函数。因为服务器需要接收客户端的请求,所以必须告诉本地主机它打算在哪个IP地址和哪个端口上等待客户请求,因此必须调用bind函数来实现这一功能。而对客户端来说,当它发起连接请求,服务器端接收请求后,在服务器端就保存了该客户端的IP地址和端口信息。这样,对服务器端来说,一旦建立连接之后,实际上它保存了客户端的IP地址和端口的信息,因此就可以利用所返回的套接字调用send/recv函数与客户端进行通信。


3.基于UDP(面向无连接)的socket编程
接收端:
1)创建套接字socket
2)将套接字绑定到本地地址和端口上bind
3)等待接受数据recvfrom
4)关闭套接字


发送端:
1)创建套接字(socket)
2)向服务器发送数据sendto
3)关闭套接字




4.相关函数
int WSAStartup(//初始化Ws_2_32.dll的使用,加载套接字库
  WORD wVersionRequested,
  LPWSADATA lpWSAData
);


SOCKET socket (//创建套接字
int af, 
int type, 
int protocol ); 


int bind(//绑定本地的某个地址和端口,调用成功返回0,否则返回SOCKET_ERROR
  SOCKET s,                          
  const struct sockaddr FAR *name,   
  int namelen                        
);


struct sockaddr {//sockaddr结构
  u_short    sa_family;
  char       sa_data[14];
};  


struct sockaddr_in{//在TCP/IP中可以使用sockaddr_in代替sockaddr
 short sin_family;
 unsigned short sin_port;
 IN_ADDR sin_addr;
 char sin_zero[8];};




struct in_addr {
  union {
          struct { u_char s_b1,s_b2,s_b3,s_b4; }   S_un_b;
          struct { u_short s_w1,s_w2; }            S_un_w;
          u_long                                   S_addr;
  } S_un;
};


unsigned long inet_addr (//将一个带点地址的字符串转换为IN_ADDR结构
const char *cp ); 




char FAR * inet_ntoa(//与上述函数功能相反,将IN_ADDR结构转化为字符串
  struct   in_addr in  
);


int listen(//将指定套接字设置监听模式
  SOCKET s,    
  int backlog  
);


SOCKET accept(//接受客户端发送的连接请求
  SOCKET s,
  struct sockaddr FAR *addr,
  int FAR *addrlen
);


int send(//发送数据
  SOCKET s,              
  const char FAR *buf,  
  int len,               
  int flags              
);


int recv(//接收数据
  SOCKET s,       
  char FAR *buf,  
  int len,        
  int flags       
);




int connect(//讲一个特定的套接字建立连接
  SOCKET s,                          
  const struct sockaddr FAR *name,  
  int namelen                        
);


int recvfrom(//接受一个数据报信息并保存源地址
  SOCKET s,                   
  char FAR* buf,              
  int len,                    
  int flags,                  
  struct sockaddr FAR *from,  
  int FAR *fromlen            
);


int sendto(//向一个特定的目的地发送数据
  SOCKET s,                        
  const char FAR *buf,            
  int len,                         
  int flags,                       
  const struct sockaddr FAR *to,  
  int tolen                        
);


u_short htons(//把一个u_short类型的值从主机字节顺序转换为TCP/IP网络字节顺序
  u_short hostshort  
);


u_long htonl(//把一个u_long类型的值从主机字节顺序转换为TCP/IP网络字节顺序
  u_long hostlong  
);




5.基于TCP的网络应用程序的编写
5.1服务器段程序
#include<Winsock2.h>
#include<stdio.h>

void main(){
//加载套接字库
WORD wVersionRequested;
WSADATA wsaData;
int err;

wVersionRequested = MAKEWORD(1,1);

err = WSAStartup(wVersionRequested, &wsaData);
if( err != 0){
return;
}

if(LOBYTE(wsaData.wVersion) != 1 ||
HIBYTE(wsaData.wVersion) != 1){
WSACleanup();
return;
}

//创建用于监听的套接字

SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
//绑定套接字
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
//将套接字设为监听模式,准备接收客户请求
listen(sockSrv,5);

SOCKADDR_IN addrClient;
int len = sizeof(SOCKADDR);

while(1){
//等待客户请求到来
SOCKET sockConn = accept(sockSrv,(SOCKADDR*)&addrClient,&len);
char sendBuf[100];
sprintf(sendBuf,"Welcome %s to http://www.sunxin,org",
inet_ntoa(addrClient.sin_addr));
//发送数据
send(sockConn,sendBuf,strlen(sendBuf)+1,0);
char recvBuf[100];
//接收数据
recv(sockConn,recvBuf,100,0);
//打印接收的数据
printf("%s\n",recvBuf);
//关闭套接字
closesocket(sockConn);
}
}




5.2客户端程序
#include<Winsock2.h>
#include<stdio.h>
void main(){
//加载套接字库
WORD wVersionRequested;
WSADATA wsaData;
int err;

wVersionRequested = MAKEWORD(1,1);

err = WSAStartup(wVersionRequested, &wsaData);
if( err != 0){
return;
}

if(LOBYTE(wsaData.wVersion) != 1 ||
HIBYTE(wsaData.wVersion) != 1){
WSACleanup();
return;
}
//创建套接字
SOCKET sockClient = socket(AF_INET,SOCK_STREAM,0);

SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr= inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
//向服务器发出连接请求
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
//接收数据
char recvBuf[100];
recv(sockClient,recvBuf,100,0);
printf("%s\n",recvBuf);
//发送数据
send(sockClient,"This is lisi",strlen("this is lisi")+1,0);
closesocket(sockClient);
WSACleanup();
}
要加入ws2_32.lib库文件


6.2基于UDP的网络应用程序的编写

后面会有一个多线程聊天程序的编写

详见http://blog.csdn.net/walkerkalr/article/details/19510909




==参考VC++深入详解