SOCKET API的程序

作者在 2009-03-16 11:29:46 发布以下内容
我改写了MSDN上的代码。作为socket之间通信的例子
可以看到这是一个阻塞式的通信过程。
 
“127.0.0.1”这个IP是内部回环测试的IP号。
代码涉及以下几个socket 常用的api 函数。
WSAStartup
socket
bind
accept
recv
send
WSACleanup
 
//下面是服务器的代码.程序使用的是TCP协议通信
//在库中加入 wsock32.lib
#include <stdio.h>
#include "winsock2.h"//这是一个SOCKET的头文件
void main()
{
  //----------------------
  // Initialize Winsock.
  char getbuf[1024];
  WSADATA wsaData;
  int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);//这个函数是初始化socket版本的函数,一定要用
  if (iResult != NO_ERROR)
    printf("Error at WSAStartup()\n");
  //----------------------
  // Create a SOCKET for listening for
  // incoming connection requests.
  SOCKET ListenSocket;
  ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//这里初始化了socket的通信方式为流式
  if (ListenSocket == INVALID_SOCKET)
  {
    printf("Error at socket(): %ld\n", WSAGetLastError());
    WSACleanup();
    return;
  }
  //----------------------
  // The sockaddr_in structure specifies the address family,
  // IP address, and port for the socket that is being bound.
  sockaddr_in service;
  service.sin_family = AF_INET;
  service.sin_addr.s_addr = inet_addr("127.0.0.1");
  service.sin_port = htons(27015);
  if (bind( ListenSocket,
    (SOCKADDR*) &service,
    sizeof(service)) == SOCKET_ERROR)
  {
    printf("bind() failed.\n");
    closesocket(ListenSocket);
    return;
  }
  //----------------------
  // Listen for incoming connection requests.
  // on the created socket
  if (listen( ListenSocket, 1 ) == SOCKET_ERROR)
    printf("Error listening on socket.\n");
  //----------------------
  // Create a SOCKET for accepting incoming requests.
  SOCKET AcceptSocket;
  printf("Waiting for client to connect...\n");

  //----------------------
  // Accept the connection.
  while(1)
  {
    AcceptSocket = SOCKET_ERROR;
    while( AcceptSocket == SOCKET_ERROR )
 {
      AcceptSocket = accept( ListenSocket, NULL, NULL );
    }
    printf("Client connected.\n");
    //ListenSocket = AcceptSocket;
    break;
  }
  int bytesrecv;
  int bytesSent;
  char m_ack[4]="ACK";
  while(1)
  {
    bytesrecv=recv(AcceptSocket,getbuf,1024,0);//流式使用recv接收数据
    if(bytesrecv!=-1)
 {
   if(bytesrecv<=1024)
    getbuf[bytesrecv]='\0';
   printf("%s\n",getbuf);
   bytesSent = send( AcceptSocket, m_ack, strlen(m_ack), 0 );//流式使用send发送数据
 }
 if(bytesrecv==SOCKET_ERROR)
 { 
  printf("Client close.\n");
  break;
 }
  }
  system("pause");
  WSACleanup();
  return;
}
/*
以下是客户端代码
同样记得在库中加入 wsock32.lib
*/

#include <stdio.h>
#include <conio.h>
#include "winsock2.h"
void main()
{
  //----------------------
  // Initialize Winsock
  WSADATA wsaData;
  int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
  if (iResult != NO_ERROR)
  {
    printf("Error at WSAStartup()\n");
    system("pause");
 return;
  }
  //----------------------
  // Create a SOCKET for connecting to server
  SOCKET ConnectSocket;
  ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (ConnectSocket == INVALID_SOCKET)
  {
    printf("Error at socket(): %ld\n", WSAGetLastError());
    WSACleanup();
 system("pause");
    return;
  }
  //----------------------
  // The sockaddr_in structure specifies the address family,
  // IP address, and port of the server to be connected to.
  sockaddr_in clientService;
  clientService.sin_family = AF_INET;
  clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
  clientService.sin_port = htons( 27015 );
  //----------------------
  // Connect to server.
  if ( connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR)
  {
    printf( "Failed to connect.\n" );
    WSACleanup();
 system("pause");
    return;
  }
 
  //----------------------
  // Declare and initialize variables.
  int bytesSent;
  int bytesRecv = SOCKET_ERROR;
  char sendbuf[1024] = "Client: Sending data.";
  char recvbuf[1024] = "";
  //----------------------
  printf("connect ok!\n");
  bytesSent = send( ConnectSocket, sendbuf, strlen(sendbuf), 0 );
  bytesRecv = recv( ConnectSocket, recvbuf, 32, 0 );
  int putin=0;
  char inchar;
  while(bytesRecv!=SOCKET_ERROR)
  {
    if ( bytesRecv == -1 || bytesRecv == WSAECONNRESET )
 {
      printf( "Connection Closed.\n");
      break;
    }
 putin=0;
    while(1)
 {
     inchar=getch();
     if(inchar==13)
  {
   printf("\n");
   break;
  }
  else
  {
   sendbuf[putin++]=inchar;
      putch(inchar);
  }
 }
 sendbuf[putin]='\0';
 bytesSent = send( ConnectSocket, sendbuf, strlen(sendbuf), 0 );
 bytesRecv = recv( ConnectSocket, recvbuf, 1024, 0 );
 if(bytesRecv==-1)
 {
  printf("server close\n");
  break;
 }
  }
  system("pause");
  WSACleanup();
  return;
}
注:先运行服务器端程序,再运行客户端程序。这样就完成了连接。在客户端程序输入字符回车后数据发到服务器程序。服务器程序显示客户端发送数据。
 
以下是使用UDP数据报的连接方式。
服务器程序:
同样记得在库中加入 wsock32.lib
#include <stdio.h>
#include "winsock2.h"
void main() {
  WSADATA wsaData;
  SOCKET RecvSocket;
  sockaddr_in RecvAddr;
  int Port = 27015;
  char RecvBuf[1024];
  int  BufLen = 1024;
  sockaddr_in SenderAddr;
  int SenderAddrSize = sizeof(SenderAddr);
  //-----------------------------------------------
  // Initialize Winsock
  WSAStartup(MAKEWORD(2,2), &wsaData);
  //-----------------------------------------------
  // Create a receiver socket to receive datagrams
  RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  //-----------------------------------------------
  // Bind the socket to any address and the specified port.
  RecvAddr.sin_family = AF_INET;
  RecvAddr.sin_port = htons(Port);
  RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  bind(RecvSocket, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr));
  //-----------------------------------------------
  // Call the recvfrom function to receive datagrams
  // on the bound socket.
  printf("Receiving datagrams...\n");
  while(1)
  {
  recvfrom(RecvSocket,
    RecvBuf,
    BufLen,
    0,
    (SOCKADDR *)&SenderAddr,
    &SenderAddrSize);
  printf("%s\n",RecvBuf);
  }
  //-----------------------------------------------
  // Close the socket when finished receiving datagrams
  printf("Finished receiving. Closing socket.\n");
  closesocket(RecvSocket);
  //-----------------------------------------------
  // Clean up and exit.
  printf("Exiting.\n");
  WSACleanup();
  return;
}
以下是客户端代码。
同样记得在库中加入 wsock32.lib
#include <stdio.h>
#include <conio.h>
#include "winsock2.h"
void main()
{
 
  WSADATA wsaData;
  SOCKET SendSocket;
  sockaddr_in RecvAddr;
  int Port = 27015;
  char SendBuf[1024];
  int BufLen = 1024;
  //---------------------------------------------
  // Initialize Winsock
  WSAStartup(MAKEWORD(2,2), &wsaData);
  //---------------------------------------------
  // Create a socket for sending data
  SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  //---------------------------------------------
  // Set up the RecvAddr structure with the IP address of
  // the receiver (in this example case "123.456.789.1")
  // and the specified port number.
  RecvAddr.sin_family = AF_INET;
  RecvAddr.sin_port = htons(Port);
  RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  //---------------------------------------------
  // Send a datagram to the receiver
  printf("Sending a datagram to the receiver...\n");
  int inchar=0;
  int inlen=0;
  while(1)
  {
   inlen=0;
   while(inchar!=13)
   {
 inchar=getch();
 if(inchar==27)
 {
  printf("Exiting.\n");
        WSACleanup();
  return;
 }
    SendBuf[inlen++]=inchar;
 printf("%c",inchar);
   }
   printf("\n");
   SendBuf[inlen]='\0';
   inchar='\0';
  sendto(SendSocket,
    SendBuf,
    BufLen,
    0,
    (SOCKADDR *) &RecvAddr,
    sizeof(RecvAddr));
  }
  //---------------------------------------------
  // When the application is finished sending, close the socket.
  printf("Finished sending. Closing socket.\n");
  closesocket(SendSocket);
  //---------------------------------------------
  // Clean up and quit.
  printf("Exiting.\n");
  WSACleanup();
  return;
}
socket的内回环也可以作为进程间通信的方式。以上代码可以看出socket通信是使用阻塞方式的(在服务器的recvfrom处做个中断就可以看出来了。程序会停留在那里等待接收数据)在win32或linux下可以使用多线程来实现非阻塞通信。

 
技术 | 阅读 8351 次
文章评论,共0条
游客请输入验证码
浏览60394次
文章分类