3个学习Socket编程的简单例子:TCP Server/Client, Select

本文提供了三个简单的Socket编程示例,包括TCP客户端、TCP服务器及采用Select的TCP服务器,旨在帮助读者快速入门Socket编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以前都是采用ACE的编写网络应用,最近由于工作需要,需要直接只用socket接口编写CS的代码,重新学习这方面的知识,给出自己所用到的3个简单例子,都是拷贝别人的程序。如果你能完全理解这3个例子,估计socket编程就已经基本入门了。

      建议:1) 多多查查所用到的网络接口; 2) 最好有一本书,如UNIX环境高级编程,UNIX网络编程,可查询;3) 可以直接使用书上的例子更好。

      TCP Client代码:

view plaincopy to clipboardprint?
#include   <sys/stat.h>     
#include   <sys/types.h>     
#include   <sys/socket.h>     
#include   <stdio.h>     
#include   <malloc.h>     
#include   <netdb.h>     
#include   <fcntl.h>  
#include   <unistd.h>  
#include   <netinet/in.h>  
#include   <arpa/inet.h>  
#define    RES_LENGTH  10240 //接受字符的最大长度  
int     connect_socket(char * server,int serverPort);  
int     send_msg(int sockfd,char * sendBuff);  
char *  recv_msg(int sockfd);  
int     close_socket(int sockfd);  
int main(int argc, char ** argv)  
{  
    int   sockfd=0;  
    char  sendMsg[30]="abc.org/r/n/r";  
    char* res;  
    int   port = 4242;  
    char  ip[128] = {0};  
    strncpy(ip, "127.0.0.1", 128);  
    if(argc > 2)  
    {  
        strncpy(ip, argv[1], 128);  
        port = atoi(argv[2]);  
        printf("Input IP: %s, port : %d/n", ip, port);  
    }  
    else if(argc > 1)  
    {     
        port = atoi(argv[1]);  
        printf("Input port : %d/n", port);  
    }  
    sockfd=connect_socket(ip, port);  
      
    send_msg(sockfd,sendMsg);  
    /* res=recv_msg(sockfd); */ 
      
    printf("return from recv function/n");  
    printf(res);  
    free(res);  
    close_socket(sockfd);  
    return 0;  
}  
/************************************************************ 
 * 连接SOCKET服务器,如果出错返回-1,否则返回socket处理代码 
 * server:服务器地址(域名或者IP),serverport:端口 
 * ********************************************************/ 
int    connect_socket(char * server,int serverPort){  
    int    sockfd=0;  
    struct    sockaddr_in    addr;  
    struct    hostent        * phost;  
    //向系统注册,通知系统建立一个通信端口  
    //AF_INET表示使用IPv4协议  
    //SOCK_STREAM表示使用TCP协议  
    if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0){  
        herror("Init socket error!");  
        return -1;  
    }  
    bzero(&addr,sizeof(addr));  
    addr.sin_family = AF_INET;  
    addr.sin_port = htons(serverPort);  
    addr.sin_addr.s_addr = inet_addr(server);//按IP初始化  
      
    if(addr.sin_addr.s_addr == INADDR_NONE){//如果输入的是域名  
        phost = (struct hostent*)gethostbyname(server);  
        if(phost==NULL){  
            herror("Init socket s_addr error!");  
            return -1;  
        }  
        addr.sin_addr.s_addr =((struct in_addr*)phost->h_addr)->s_addr;  
    }  
    if(connect(sockfd,(struct sockaddr*)&addr, sizeof(addr))<0)  
    {  
        perror("Connect server fail!");  
        return -1; //0表示成功,-1表示失败  
    }  
    else 
        return sockfd;  
}  
/************************************************************** 
 * 发送消息,如果出错返回-1,否则返回发送的字符长度 
 * sockfd:socket标识,sendBuff:发送的字符串 
 * *********************************************************/ 
int send_msg(int sockfd,char * sendBuff)  
{  
    int sendSize=0;  
    if((sendSize=send(sockfd,sendBuff,strlen(sendBuff),0))<=0){  
        herror("Send msg error!");  
        return -1;  
    }else 
        return sendSize;  
}  
/**************************************************************** 
 *接受消息,如果出错返回NULL,否则返回接受字符串的指针(动态分配,注意释放) 
 *sockfd:socket标识 
 * *********************************************************/ 
char* recv_msg(int sockfd){  
    char * response;  
    int  flag=0,recLenth=0;  
    response=(char *)malloc(RES_LENGTH);  
    memset(response,0,RES_LENGTH);  
      
    for(flag=0;;)  
    {  
        printf("======recv data:/n");  
        if(( recLenth=recv(sockfd,response+flag,RES_LENGTH-flag,0))==-1 )  
        {  
            free(response);  
            printf("Return value : %d/n", recLenth);  
            perror("Recv msg error : ");  
            return NULL;  
        }  
        else if(recLenth==0)  
            break;  
        else 
        {  
            printf("%d char recieved data : %s./n", recLenth, response+flag);  
            flag+=recLenth;  
            recLenth=0;  
        }  
    }  
    printf("Return value : %d/n", recLenth);  
    response[flag]='/0';  
    return response;  
}  
/************************************************** 
 *关闭连接 
 * **********************************************/ 
int close_socket(int sockfd)  
{  
    close(sockfd);  
    return 0;  

#include   <sys/stat.h>  
#include   <sys/types.h>  
#include   <sys/socket.h>  
#include   <stdio.h>  
#include   <malloc.h>  
#include   <netdb.h>  
#include   <fcntl.h>
#include   <unistd.h>
#include   <netinet/in.h>
#include   <arpa/inet.h>
#define    RES_LENGTH  10240 //接受字符的最大长度
int     connect_socket(char * server,int serverPort);
int     send_msg(int sockfd,char * sendBuff);
char *  recv_msg(int sockfd);
int     close_socket(int sockfd);
int main(int argc, char ** argv)
{
 int   sockfd=0;
 char  sendMsg[30]="abc.org/r/n/r";
 char* res;
 int   port = 4242;
 char  ip[128] = {0};
 strncpy(ip, "127.0.0.1", 128);
 if(argc > 2)
 {
  strncpy(ip, argv[1], 128);
  port = atoi(argv[2]);
  printf("Input IP: %s, port : %d/n", ip, port);
 }
 else if(argc > 1)
 { 
  port = atoi(argv[1]);
  printf("Input port : %d/n", port);
 }
 sockfd=connect_socket(ip, port);
 
 send_msg(sockfd,sendMsg);
 /* res=recv_msg(sockfd); */
 
 printf("return from recv function/n");
 printf(res);
 free(res);
 close_socket(sockfd);
 return 0;
}
/************************************************************
 * 连接SOCKET服务器,如果出错返回-1,否则返回socket处理代码
 * server:服务器地址(域名或者IP),serverport:端口
 * ********************************************************/
int    connect_socket(char * server,int serverPort){
 int    sockfd=0;
 struct    sockaddr_in    addr;
 struct    hostent        * phost;
 //向系统注册,通知系统建立一个通信端口
 //AF_INET表示使用IPv4协议
 //SOCK_STREAM表示使用TCP协议
 if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0){
  herror("Init socket error!");
  return -1;
 }
 bzero(&addr,sizeof(addr));
 addr.sin_family = AF_INET;
 addr.sin_port = htons(serverPort);
 addr.sin_addr.s_addr = inet_addr(server);//按IP初始化
 
 if(addr.sin_addr.s_addr == INADDR_NONE){//如果输入的是域名
  phost = (struct hostent*)gethostbyname(server);
  if(phost==NULL){
   herror("Init socket s_addr error!");
   return -1;
  }
  addr.sin_addr.s_addr =((struct in_addr*)phost->h_addr)->s_addr;
 }
 if(connect(sockfd,(struct sockaddr*)&addr, sizeof(addr))<0)
 {
  perror("Connect server fail!");
  return -1; //0表示成功,-1表示失败
 }
 else
  return sockfd;
}
/**************************************************************
 * 发送消息,如果出错返回-1,否则返回发送的字符长度
 * sockfd:socket标识,sendBuff:发送的字符串
 * *********************************************************/
int send_msg(int sockfd,char * sendBuff)
{
 int sendSize=0;
 if((sendSize=send(sockfd,sendBuff,strlen(sendBuff),0))<=0){
  herror("Send msg error!");
  return -1;
 }else
  return sendSize;
}
/****************************************************************
 *接受消息,如果出错返回NULL,否则返回接受字符串的指针(动态分配,注意释放)
 *sockfd:socket标识
 * *********************************************************/
char* recv_msg(int sockfd){
 char * response;
 int  flag=0,recLenth=0;
 response=(char *)malloc(RES_LENGTH);
 memset(response,0,RES_LENGTH);
 
 for(flag=0;;)
 {
  printf("======recv data:/n");
  if(( recLenth=recv(sockfd,response+flag,RES_LENGTH-flag,0))==-1 )
  {
   free(response);
   printf("Return value : %d/n", recLenth);
   perror("Recv msg error : ");
   return NULL;
  }
  else if(recLenth==0)
   break;
  else
  {
   printf("%d char recieved data : %s./n", recLenth, response+flag);
   flag+=recLenth;
   recLenth=0;
  }
 }
 printf("Return value : %d/n", recLenth);
 response[flag]='/0';
 return response;
}
/**************************************************
 *关闭连接
 * **********************************************/
int close_socket(int sockfd)
{
 close(sockfd);
 return 0;
}
 

      TCP Server:

view plaincopy to clipboardprint?
#include <unistd.h> /* fork, close */  
#include <stdlib.h> /* exit */  
#include <string.h> /* strlen */  
#include <stdio.h> /* perror, fdopen, fgets */  
#include <sys/socket.h>  
#include <sys/wait.h> /* waitpid */  
#include <netdb.h> /* getaddrinfo */  
#define die(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)  
#define PORT "4242"  
#define NUM_CHILDREN 3  
#define MAXLEN 1024  
int readline(int fd, char *buf, int maxlen); // forward declaration  
int recvdata(int fd, char *buf, int maxlen); // forward declaration  
int main(int argc, char** argv)  
{  
    int i, n, sockfd, clientfd;  
    int yes = 1;    // used in setsockopt(2)  
    struct addrinfo *ai;  
    struct sockaddr_in *client;  
    socklen_t client_t;  
    pid_t cpid;     // child pid  
    char line[MAXLEN];  
    char cpid_s[32];  
    char welcome[32];  
    /* Create a socket and get its file descriptor -- socket(2) */ 
    sockfd = socket(AF_INET, SOCK_STREAM, 0);  
    if (sockfd == -1) {  
        die("Couldn't create a socket");  
    }  
    /* Prevents those dreaded "Address already in use" errors */ 
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&yes, sizeof(int)) == -1) {  
        die("Couldn't setsockopt");  
    }  
    /* Fill the address info struct (host + port) -- getaddrinfo(3) */ 
    if (getaddrinfo(NULL, PORT, NULL, &ai) != 0) {   // get localhost   
        die("Couldn't get address");  
    }  
    /* Assign address to this socket's fd */ 
    if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) != 0) {  // only bind on localhost ip  
        die("Couldn't bind socket to address");  
    }  
    /* Free the memory used by our address info struct */ 
    freeaddrinfo(ai);  
    /* Mark this socket as able to accept incoming connections */ 
    /* printf("Process %d Listening/n", getpid()); */ 
    if (listen(sockfd, 10) == -1) {  
        die("Couldn't make socket listen");  
    }  
    printf("One new connection is coming!/n");  
    /* Fork you some child processes. */ 
    for (i = 0; i < NUM_CHILDREN; i++) {  
        cpid = fork();  
        if (cpid == -1) {  
            die("Couldn't fork");  
        }  
        if (cpid == 0) { // We're in the child ...  
            for (;;) { // Run forever ...  
                /* Necessary initialization for accept(2) */ 
                client_t = sizeof client;  
                /* Blocks! */ 
                printf("Waiting new connection!/n");  
                clientfd = accept(sockfd, (struct sockaddr *)&client, &client_t);  
                if (clientfd == -1) {  
                    die("Couldn't accept a connection");  
                }  
                /* Send a welcome message/prompt */ 
                bzero(cpid_s, 32);  
                bzero(welcome, 32);  
                sprintf(cpid_s, "%d", getpid());  
                sprintf(welcome, "Child %s echo> ", cpid_s);  
                send(clientfd, welcome, strlen(welcome), 0);  
                /* Read a line from the client socket ... */ 
                /* n = readline(clientfd, line, MAXLEN); 
                if (n == -1) { 
                    die("Couldn't read line from connection"); 
                }                                                 */ 
              
                n = recvdata(clientfd, line, MAXLEN);  
                printf("recieve data: %s", line);  
                /* ... and echo it back */ 
                send(clientfd, line, n, 0);  
                /* Clean up the client socket */ 
                close(clientfd);  
                printf("Close client socket./n");  
            }  
        }  
    }  
    /* Sit back and wait for all child processes to exit */ 
    while (waitpid(-1, NULL, 0) > 0);  
    /* Close up our socket */ 
    close(sockfd);  
    printf("Close server socket./n");  
    return 0;  
}  
    
/** 
 * Simple utility function that reads a line from a file descriptor fd, 
 * up to maxlen bytes -- ripped from Unix Network Programming, Stevens. 
 */ 
int readline(int fd, char *buf, int maxlen)  
{  
    int n, rc;  
    char c;  
    for (n = 1; n < maxlen; n++) {  
        if ((rc = read(fd, &c, 1)) == 1) {  
            *buf++ = c;  
            if (c == '/n')  
                break;  
        } else if (rc == 0) {  
            if (n == 1)  
                return 0; // EOF, no data read  
            else 
                break; // EOF, read some data  
        } else 
            return -1; // error  
    }  
    *buf = '/0'; // null-terminate  
      
    return n;  
}  
int recvdata(int fd, char *buf, int maxlen)  
{  
    return recv(fd, buf, maxlen, 0);  

#include <unistd.h> /* fork, close */
#include <stdlib.h> /* exit */
#include <string.h> /* strlen */
#include <stdio.h> /* perror, fdopen, fgets */
#include <sys/socket.h>
#include <sys/wait.h> /* waitpid */
#include <netdb.h> /* getaddrinfo */
#define die(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
#define PORT "4242"
#define NUM_CHILDREN 3
#define MAXLEN 1024
int readline(int fd, char *buf, int maxlen); // forward declaration
int recvdata(int fd, char *buf, int maxlen); // forward declaration
int main(int argc, char** argv)
{
 int i, n, sockfd, clientfd;
 int yes = 1;    // used in setsockopt(2)
 struct addrinfo *ai;
 struct sockaddr_in *client;
 socklen_t client_t;
 pid_t cpid;     // child pid
 char line[MAXLEN];
 char cpid_s[32];
 char welcome[32];
 /* Create a socket and get its file descriptor -- socket(2) */
 sockfd = socket(AF_INET, SOCK_STREAM, 0);
 if (sockfd == -1) {
  die("Couldn't create a socket");
 }
 /* Prevents those dreaded "Address already in use" errors */
 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&yes, sizeof(int)) == -1) {
  die("Couldn't setsockopt");
 }
 /* Fill the address info struct (host + port) -- getaddrinfo(3) */
 if (getaddrinfo(NULL, PORT, NULL, &ai) != 0) {   // get localhost
  die("Couldn't get address");
 }
 /* Assign address to this socket's fd */
 if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) != 0) {  // only bind on localhost ip
  die("Couldn't bind socket to address");
 }
 /* Free the memory used by our address info struct */
 freeaddrinfo(ai);
 /* Mark this socket as able to accept incoming connections */
 /* printf("Process %d Listening/n", getpid()); */
 if (listen(sockfd, 10) == -1) {
  die("Couldn't make socket listen");
 }
 printf("One new connection is coming!/n");
 /* Fork you some child processes. */
 for (i = 0; i < NUM_CHILDREN; i++) {
  cpid = fork();
  if (cpid == -1) {
   die("Couldn't fork");
  }
  if (cpid == 0) { // We're in the child ...
   for (;;) { // Run forever ...
    /* Necessary initialization for accept(2) */
    client_t = sizeof client;
    /* Blocks! */
    printf("Waiting new connection!/n");
    clientfd = accept(sockfd, (struct sockaddr *)&client, &client_t);
    if (clientfd == -1) {
     die("Couldn't accept a connection");
    }
    /* Send a welcome message/prompt */
    bzero(cpid_s, 32);
    bzero(welcome, 32);
    sprintf(cpid_s, "%d", getpid());
    sprintf(welcome, "Child %s echo> ", cpid_s);
    send(clientfd, welcome, strlen(welcome), 0);
    /* Read a line from the client socket ... */
    /* n = readline(clientfd, line, MAXLEN);
    if (n == -1) {
     die("Couldn't read line from connection");
    }                                                 */
   
    n = recvdata(clientfd, line, MAXLEN);
    printf("recieve data: %s", line);
    /* ... and echo it back */
    send(clientfd, line, n, 0);
    /* Clean up the client socket */
    close(clientfd);
    printf("Close client socket./n");
   }
  }
 }
 /* Sit back and wait for all child processes to exit */
 while (waitpid(-1, NULL, 0) > 0);
 /* Close up our socket */
 close(sockfd);
 printf("Close server socket./n");
 return 0;
}
 
/**
 * Simple utility function that reads a line from a file descriptor fd,
 * up to maxlen bytes -- ripped from Unix Network Programming, Stevens.
 */
int readline(int fd, char *buf, int maxlen)
{
 int n, rc;
 char c;
 for (n = 1; n < maxlen; n++) {
  if ((rc = read(fd, &c, 1)) == 1) {
   *buf++ = c;
   if (c == '/n')
    break;
  } else if (rc == 0) {
   if (n == 1)
    return 0; // EOF, no data read
   else
    break; // EOF, read some data
  } else
   return -1; // error
 }
 *buf = '/0'; // null-terminate
 
 return n;
}
int recvdata(int fd, char *buf, int maxlen)
{
 return recv(fd, buf, maxlen, 0);
}
 

      采用Select的TCP Server:

view plaincopy to clipboardprint?
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <errno.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#define MYPORT 1234    // the port users will be connecting to  
#define BACKLOG 5     // how many pending connections queue will hold  
#define BUF_SIZE 1024  
int fd_A[BACKLOG];    // accepted connection fd  
int conn_amount;      // current connection amount  
void showclient()  
{  
    int i;  
    printf("client amount: %d/n", conn_amount);  
    for (i = 0; i < BACKLOG; i++) {  
        printf("[%d]:%d  ", i, fd_A[i]);  
    }  
    printf("/n/n");  
}  
int main(void)  
{  
    int sock_fd, new_fd;             // listen on sock_fd, new connection on new_fd  
    struct sockaddr_in server_addr;  // server address information  
    struct sockaddr_in client_addr;  // connector's address information  
    socklen_t sin_size;  
    int yes = 1;  
    char buf[BUF_SIZE];  
    int ret;  
    int i;  
    if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {  
        perror("socket");  
        exit(1);  
    }  
    if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {  
        perror("setsockopt");  
        exit(1);  
    }  
    server_addr.sin_family = AF_INET;         // host byte order  
    server_addr.sin_port = htons(MYPORT);     // short, network byte order  
    server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP  
    memset(server_addr.sin_zero, '/0', sizeof(server_addr.sin_zero));  
    if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {  
        perror("bind");  
        exit(1);  
    }  
    if (listen(sock_fd, BACKLOG) == -1) {  
        perror("listen");  
        exit(1);  
    }  
    printf("listen port %d/n", MYPORT);  
    fd_set fdsr;  
    int maxsock;  
    struct timeval tv;  
    conn_amount = 0;  
    sin_size = sizeof(client_addr);  
    maxsock = sock_fd;  
    while (1)   
    {  
        // initialize file descriptor set  
        FD_ZERO(&fdsr);  
        FD_SET(sock_fd, &fdsr);  // add fd  
        // timeout setting  
        tv.tv_sec = 30;  
        tv.tv_usec = 0;  
        // add active connection to fd set  
        for (i = 0; i < BACKLOG; i++) {  
            if (fd_A[i] != 0) {  
                FD_SET(fd_A[i], &fdsr);  
            }  
        }  
        ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);  
        if (ret < 0) {          // error  
            perror("select");  
            break;  
        } else if (ret == 0) {  // time out  
            printf("timeout/n");  
            continue;  
        }  
        // check every fd in the set  
        for (i = 0; i < conn_amount; i++)   
        {  
            if (FD_ISSET(fd_A[i], &fdsr)) // check which fd is ready  
            {  
                ret = recv(fd_A[i], buf, sizeof(buf), 0);  
                if (ret <= 0)   
                {        // client close  
                    printf("ret : %d and client[%d] close/n", ret, i);  
                    close(fd_A[i]);  
                    FD_CLR(fd_A[i], &fdsr);  // delete fd   
                    fd_A[i] = 0;  
                    conn_amount--;  
                }  
                else   
                {        // receive data  
                    if (ret < BUF_SIZE)  
                        memset(&buf[ret], '/0', 1); // add NULL('/0')  
                    printf("client[%d] send:%s/n", i, buf);  
                }  
            }  
        }  
        // check whether a new connection comes  
        if (FD_ISSET(sock_fd, &fdsr))  // accept new connection   
        {  
            new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);  
            if (new_fd <= 0)   
            {  
                perror("accept");  
                continue;  
            }  
            // add to fd queue  
            if (conn_amount < BACKLOG)   
            {  
                fd_A[conn_amount++] = new_fd;  
                printf("new connection client[%d] %s:%d/n", conn_amount,  
                        inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));  
                if (new_fd > maxsock)  // update the maxsock fd for select function  
                    maxsock = new_fd;  
            }  
            else   
            {  
                printf("max connections arrive, exit/n");  
                send(new_fd, "bye", 4, 0);  
                close(new_fd);  
                break;     
            }  
        }  
        showclient();  
    }  
    // close other connections  
    for (i = 0; i < BACKLOG; i++)   
    {  
        if (fd_A[i] != 0)   
        {  
            close(fd_A[i]);  
        }  
    }  
    exit(0);  


本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/zhenjing/archive/2009/11/05/4770490.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值