linux TCP socket 執行個體

來源:互聯網
上載者:User
0:TCP/IP協議棧與資料包封裝CP/IP網路通訊協定棧分為應用程式層(Application)、傳輸層(Transport)、網路層(Network)和鏈路層(Link)四層。
不同的協議層對資料包有不同的稱謂, 在傳輸層叫做段(segment)在網路層叫做資料報(datagram),在 鏈路層叫做幀(frame)。資料封裝成幀後發到傳輸介質上,到達目的主機後每層協議再剝掉相應的首部,最後將應用程式層資料交給應用程式處理。。IP地址是標識網路中不同主機的地址,而連接埠號碼就是同一台主機上標識不同進程的地址, IP地址和連接埠號碼合起來標識網路中唯一的進程。
1:基於TCP服務端和用戶端系統調用
由於用戶端不需要固定的連接埠號碼,因此不必調用bind(),用戶端的連接埠號碼由核心自動分配。注意,用戶端不是不允許調用bind(),只是沒有必要調用bind()固定一個連接埠號碼,伺服器也不是必須調用bind(),但如果伺服器不調用bind(),核心會自動給伺服器分配監聽連接埠,每次啟動伺服器時連接埠號碼都不一樣,用戶端要串連伺服器就會遇到麻煩。
2:socket 地址說明Generic Socket Address Structures通用socket address
struct sockaddr {sa_family_t sa_family; /* Address family (AF_* constant) */char sa_data[14]; /* Socket address (size variesaccording to socket domain) */};struct sockaddr_in { /* IPv4 socket address */sa_family_t sin_family; /* Address family (AF_INET) */in_port_t sin_port; /* Port number */struct in_addr sin_addr; /* IPv4 address */unsigned char __pad[X]; /* Pad to size of 'sockaddr'structure (16 bytes) */};struct in_addr { /* IPv4 4-byte address */in_addr_t s_addr; /* Unsigned 32-bit integer */};


在linux socket編程中使用的socket地址都為通用格式即:struct sockaddr
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);Returns 0 on success, or –1 on error
對於IPv4,family參數指定為AF_INET。
對於TCP協議,type參數指定為SOCK_STREAM,表示面向流的傳輸協議。
對於UDP協議,type參數指定為SOCK_DGRAM,表示面向資料報的傳輸協議。
protocol參數的介紹從略,指定為0即可。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); Returns 0 on success, or –1 on errorint listen(int sockfd, int backlog); Returns 0 on success, or –1 on error int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); Returns file descriptor on success, or –1 on errorint connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);Returns 0 on success, or –1 on error 比如在bind(),accept(),connect()中的函數中都使用的是struct sockaddr地址,但是在實際的使用中使用的是:struct sockaddr_in地址。因此代碼中常用的地址格式定義如下:struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr = inet_addr("192.168.100.244");
servaddr.sin_port = htons(SERV_PORT);struct sockaddr_in中的成員struct in_addr sin_addr表示32位的IP地址。實際中多數使用點分十進位的字串表示IP地址,以下函數可以實現字串表示和in_addr表示之間轉換。

字串轉in_addr的函數:
#include <arpa/inet.h>
int inet_aton(const char *strptr, struct in_addr *addrptr);
in_addr_t inet_addr(const char *strptr);
int inet_pton(int family, const char *strptr, void *addrptr);
in_addr轉字串的函數:
char *inet_ntoa(struct in_addr inaddr);
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

3:TCP服務端和用戶端代碼架構。服務端:通過server ip和port 返回socketID
int getServerSokcketId(int argc, char *argv[]){struct sockaddr_in servaddr;int listenfd,optval = 1;;if (argc != 3){fputs("usage: ./server serverIp serverPort\n", stderr);exit(1);}listenfd = socket(AF_INET, SOCK_STREAM, 0);if(listenfd == -1){    close(listenfd);perror("create server socket ....");exit(0);}bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;//servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_addr.s_addr = inet_addr(argv[1]);servaddr.sin_port = htons(atoi(argv[2]));  if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval,sizeof(optval)) == -1)   {        close(listenfd);perror("server socket  setsockopt....");        return -1;  }if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1){perror("server bind ....");    close(listenfd);exit(0);}if(listen(listenfd, 20) == -1){perror("server listen ....");    close(listenfd);exit(0);}printf("Accepting connections ...\n");return listenfd;}
main函數調用,同時完成對用戶端的請求處理。
int main(int argc, char *argv[]){struct sockaddr_in  cliaddr;socklen_t cliaddr_len;int listenfd, acceptFd;    listenfd = getServerSokcketId(argc,argv);while(1){cliaddr_len = sizeof(cliaddr);acceptFd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);  /* Wait for connection */if (acceptFd == -1){syslog(LOG_ERR, "Failure in accept(): %s",strerror(errno));continue;           /* Try next */}else{printf("received from %s at PORT %d\n",inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port));}#if 0switch (fork()) //使用多進程處理使用者的請求{       /* Create child for each client */case -1:printf("------------------------------fork() return error\n");syslog(LOG_ERR, "111Can't create child (%s)",strerror(errno));close(acceptFd);         /* Give up on this client */break;              /* May be temporary; try next client */case 0:                 /* Child */close(listenfd);         /* Don't need copy of listening socket */handleRequest(acceptFd);printf("----handleRequest execute over--------------------\n");_exit(EXIT_SUCCESS);default:                /* Parent */close(acceptFd);         /* Don't need copy of connected socket */break;              /* Loop to accept next connection */}#endifclientProcess(acceptFd);//使用多執行緒用戶端的請求。 }}
其中函數clientProcess(acceptFd);定義如下:
void *thr_fn1(int cfd){ssize_t numRead,numSocketRead,numSocketWrite;char message[1000];while(1){if((numSocketRead = read(cfd, &message, sizeof(message))) > 0){//此處對收到的message進行處理numSocketWrite=write(cfd, &message, sizeof(message));if ((numSocketWrite != sizeof(message)) || numSocketWrite == -1) {syslog(LOG_ERR, "write() failed: %s", strerror(errno));return(EXIT_FAILURE);}}f(numSocketRead <= 0){printf("process pid:%d exit\n",getpid());close(cfd);syslog(LOG_ERR, "Error from read(): %s", strerror(errno));return(EXIT_FAILURE);}}}void clientProcess(int cfd){  pthread_t tid1;pthread_create(&tid1, NULL, thr_fn1, cfd);}

用戶端代碼

以下函數返回用戶端socketID跟服務端類似。
int getClietnSocketId(int argc, char *argv[]){struct sockaddr_in servaddr;char buf[MAXLINE];int sockfd, n;if (argc != 3){fputs("usage: ./client serverIp serverPort\n", stderr);exit(1);}sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd == -1){perror("create socket....\n");}bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(atoi(argv[2]));inet_aton(argv[1], &servaddr.sin_addr.s_addr);if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr.s_addr) <= 0){printf("set ip address error!\n");exit(0);}//inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr.s_addr);if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr))==-1){perror("connect....");exit(0);}return sockfd;}

main函數

int main(int argc, char *argv[]){int sfd=0,numRead;char  parentMsg[1000];    char  message[1000];    char buf[BUF_SIZE];    memset(&message,0,sizeof(message));    memset(&parentMsg,0,sizeof(parentMsg));sfd= getClietnSocketId(argc,argv);    if (sfd == -1)  {  errExit("inetConnect");  }    switch (fork())     {    case -1:        errExit("fork");    case 0:             /* Child: read server's response, echo on stdout */    memset(&message,0,sizeof(message));        for (;;) {        //memset(&message,0,sizeof(struct fileMessage));   mutex = pthread_mutex_lock(&mtx);   if (mutex != 0)      printf("pthread_mutex_lock");            if((numRead = read(sfd, &message, sizeof(message)))>0)            {            }   mutex = pthread_mutex_unlock(&mtx);   if (mutex!= 0)      printf("pthread_mutex_unlock");            if (numRead <= 0)                   /* Exit on EOF or error */            {            printf("server has closed!..%s\n",strerror(errno));            break;            }        }        printf("-------------fork exit, message: %s----------------------------------\n",strerror(errno));        _exit(EXIT_SUCCESS);    default:            /* Parent: write contents of stdin to socket */    while(1)    {     if((numRead = read(STDIN_FILENO, buf, BUF_SIZE))>0)    {           if((write(sfd, &parentMsg, sizeof(parentMsg))) != sizeof(parentMsg))           {           fatal("write() failed");           close(sfd)           }        }      }            }        exit(EXIT_SUCCESS);    }}
4:執行結果

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.