socket网络编程概述

来源:互联网 发布:声音模仿软件 编辑:程序博客网 时间:2024/05/01 20:11

一.套接字的类型

1.流式套接字(SOCK_STREAM)

        基于TCP协议实现的。

        提供面向连接、可靠的数据传输服务,数据无差错、无重复的发送,且按发送顺序接受。

2.数据报式套接字(SOCK_DGRAM)

        基于UDP协议。

        提供无连接服务。数据包以独立包形式发送,不提供无错保证,数据可能重复或丢失,并且接受顺序混乱。

3.原始套接字(SOCK_RAM)

二.基于TCP(面向连接)的socket编程

1.服务器端的程序流程

  1. 创建套接字(socket):该套接字用来监听。
  2. 将套接字绑定到一个本地地址和端口上(bind)。
  3. 将套接字设为监听模式,准备接受客户请求(listen)。
  4. 等待客户请求的到来,当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)。
  5. 用返回的套接字和客户端进行通信(send/recv)。
  6. 返回,等待另一客户请求。
  7. 关闭套接字。

总结如下:create socket -> bind -> listen -> accept -> send/recv -> close

2.客户端的程序流程

  1. 创建套接字(socket)。
  2. 向服务器发出连接请求(connect)。
  3. 和服务器进行通信(send/recv)。
  4. 关闭套接字。  

总结如下:create socket -> connect -> send/recv -> close

3.一个基于TCP的socket通信的例子

(1).服务器端(server)

        使用2个socket:一个sockSrv,用来监听客户请求,等待客户请求的到来;另一个是sockConn,用来和客户端通信的(发送/接受)。

#include <WinSock2.h>#include <stdio.h>#pragma comment(lib,"ws2_32.lib")void main(){WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested = MAKEWORD( 1, 1 );err = WSAStartup( wVersionRequested, &wsaData );if ( err != 0 ) {/* Tell the user that we could not find a usable *//* WinSock DLL.                                  */return;}/* Confirm that the WinSock DLL supports 2.2.*//* Note that if the DLL supports versions greater    *//* than 2.2 in addition to 2.2, it will still return *//* 2.2 in wVersion since that is the version we      *//* requested.                                        */if ( LOBYTE( wsaData.wVersion ) != 1 ||HIBYTE( wsaData.wVersion ) != 1 ) {/* Tell the user that we could not find a usable *//* WinSock DLL.                                  */WSACleanup( );return; }/* The WinSock DLL is acceptable. Proceed. *///create a socket to listenSOCKET sockSrv = socket(AF_INET,SOCK_STREAM,0);SOCKADDR_IN addrSrv;//INADDR_ANY表示IP为0.0.0.0,表示所在机器的所有地址,因为对于多网卡的机器//会有多个IP,那么用0.0.0.0进行socket的bind,则所有网卡都可监听到addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);addrSrv.sin_family=AF_INET;addrSrv.sin_port=htons(7777);//bind the socketbind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//set the socket to be listening and prepare to receive the client requestlisten(sockSrv , 5 );SOCKADDR_IN addrClient;int len = sizeof(SOCKADDR);while (1){  //wait client request  SOCKET sockConn = accept(sockSrv,(SOCKADDR*)&addrClient,&len);  char sendBuf[100]= "welcome 11";  sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(addrClient.sin_addr));  //send data  send(sockConn,sendBuf,strlen(sendBuf)+1,0);  char recvBuf[100];  //receive data  recv(sockConn,recvBuf,100,0);  printf("%s \n",recvBuf);  closesocket(sockConn);}getchar();return;}

(2).客户端(client)

       只用一个socket:sockClient,进行通信。

#include <WinSock2.h>#include <stdio.h>#pragma comment(lib,"ws2_32.lib") 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;}//create a socketSOCKET sockClient = socket(AF_INET,SOCK_STREAM,0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//服务器IPaddrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(7777);//send a connect requestconnect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//receive datachar recvBuf[100];recv(sockClient,recvBuf,100,0);printf("%s \n",recvBuf);//send datasend(sockClient,"welcome zhaolianxiang",strlen("welcome zhaolianxiang")+1,0);//close socketclosesocket(sockClient);WSACleanup();getchar();}


三.基于UDP(面向无连接)的socket编程

       基于UDP的socket编程中,其服务器端和客户端的概念不是很强化。可以把先启动的一端称为接收端(服务器端),发送数据的一端成为发送端(客户端)。

1.服务器端(接收端)的程序流程

  1. 创建套接字(socket)。
  2. 将套接字绑定到一个本地地址和端口上(bind)。
  3. 等待接受数据(recvfrom)。
  4. 关闭套接字(close)。

总结:create socket -> bind ->recvfrom ->close。

2.客户端(发送端)的程序流程

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

总结:create socket ->sendto ->close。

3.一个基于UDP的socket通信的例子

(1).接收端(服务器)

        只用一个socket:sockSrv进行通信。

#include <Winsock2.h>#include <stdio.h>#pragma comment(lib,"ws2_32.lib")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_DGRAM,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));  //绑定套接字SOCKADDR_IN addrClient;int len=sizeof(SOCKADDR);char recvBuf[100];recvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&addrClient,&len);//等待并接受数据printf("%s\n",recvBuf);closesocket(sockSrv);WSACleanup();}

(2).发送端(客户端)

       只用一个socket:sockClient进行通信。

#include <Winsock2.h>#include <stdio.h>#pragma comment(lib,"ws2_32.lib")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_DGRAM,0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");//接收方的IPaddrSrv.sin_family=AF_INET;addrSrv.sin_port=htons(6000);sendto(sockClient,"Hello",strlen("Hello")+1,0,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//发送数据closesocket(sockClient);  //关闭套接字WSACleanup();}

四.TCP socket和UDP socket的比较

       TCP socket模式:C/S模式,即客户端/服务器端。适用于一个server,多个client,即一对多。使用send/recv函数发送和接受数据。

       UDP socket模式:发送端/接收端模式,即先启动的一端为接收端。适用于一对一的情况,比如聊天。即client <----> client。使用sendto/recvfrom函数发送和接受数据。

五.一个基于UDP的简单聊天程序

(1).服务器端

#include <WinSock2.h>#include <stdio.h>#pragma comment(lib,"ws2_32.lib")void main(){WORD wVersionRequested;WSAData wsaData;int err;wVersionRequested = MAKEWORD(2,2);err = WSAStartup(wVersionRequested,&wsaData);if (err != 0){return;}if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){WSACleanup();return;}//create a socketSOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(5555);//bind the socketbind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));char recvBuf[1000];char sendBuf[1000];char tempBuf[1000];SOCKADDR_IN addrClient;int len = sizeof(SOCKADDR);while (1){//receive datarecvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&addrClient,&len);if ('q' == recvBuf[0]){sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR*)&addrClient,len);printf("chat end!\n");break;}sprintf(tempBuf,"%s say: %s",inet_ntoa(addrClient.sin_addr),recvBuf);printf("%s \n",tempBuf);//send dataprintf("pls input data:\n");gets(sendBuf);sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrClient,len);}closesocket(sockSrv);WSACleanup();getchar();};

分析:服务器端(接收端)是先接受数据,再发送数据。只有一个socket对象用来通信:sockSrv,。

(2).客户端

#include <WinSock2.h>#include <stdio.h>#pragma comment(lib,"ws2_32.lib")void main(){WORD wVersionRequested;WSAData wsaData;int err;wVersionRequested = MAKEWORD(2,2);err = WSAStartup(wVersionRequested,&wsaData);if (err != 0){return;}if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){WSACleanup();return;}SOCKET sockClient = socket(AF_INET,SOCK_DGRAM,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(5555);int len = sizeof(SOCKADDR);char recvBuf[100];char sendBuf[100];char tempBuf[100];while (1){printf("pls input data:\n");gets(sendBuf);sendto(sockClient,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)(&addrSrv),len);recvfrom(sockClient,recvBuf,100,0,(SOCKADDR*)&addrSrv,&len);if ('q' == recvBuf[0]){sendto(sockClient,"q",strlen("q")+1,0,(SOCKADDR*)&addrSrv,len);printf("chat end!\n");                        break;}sprintf(tempBuf,"%s says: %s",inet_ntoa(addrSrv.sin_addr),recvBuf);printf("%s \n",tempBuf);}closesocket(sockClient);WSACleanup();getchar();};
分析:客户端(发送端)是先发送数据,后接受数据。只用一个socket:sockClient进行通信。


	
				
		
原创粉丝点击