3个学习Socket编程的简单例子

    技术2025-09-04  12

    文章出处:http://blog.csdn.net/zhenjing/archive/2009/11/05/4770490.aspx

     

    TCP Client 代码:

     

    01.#include <sys/stat.h> 02.#include <sys/types.h> 03.#include <sys/socket.h> 04.#include <stdio.h> 05.#include <malloc.h> 06.#include <netdb.h> 07.#include <fcntl.h> 08.#include <unistd.h> 09.#include <netinet/in.h> 10.#include <arpa/inet.h> 11.#define RES_LENGTH 10240 //接受字符的最大长度 12.int connect_socket(char * server,int serverPort); 13.int send_msg(int sockfd,char * sendBuff); 14.char * recv_msg(int sockfd); 15.int close_socket(int sockfd); 16.int main(int argc, char ** argv) 17.{ 18. int sockfd=0; 19. char sendMsg[30]="abc.org/r/n/r"; 20. char* res; 21. int port = 4242; 22. char ip[128] = {0}; 23. strncpy(ip, "127.0.0.1", 128); 24. if(argc > 2) 25. { 26. strncpy(ip, argv[1], 128); 27. port = atoi(argv[2]); 28. printf("Input IP: %s, port : %d/n", ip, port); 29. } 30. else if(argc > 1) 31. { 32. port = atoi(argv[1]); 33. printf("Input port : %d/n", port); 34. } 35. sockfd=connect_socket(ip, port); 36. 37. send_msg(sockfd,sendMsg); 38. /* res=recv_msg(sockfd); */ 39. 40. printf("return from recv function/n"); 41. printf(res); 42. free(res); 43. close_socket(sockfd); 44. return 0; 45.} 46./************************************************************ 47. * 连接SOCKET服务器,如果出错返回-1,否则返回socket处理代码 48. * server:服务器地址(域名或者IP),serverport:端口 49. * ********************************************************/ 50.int connect_socket(char * server,int serverPort){ 51. int sockfd=0; 52. struct sockaddr_in addr; 53. struct hostent * phost; 54. //向系统注册,通知系统建立一个通信端口 55. //AF_INET表示使用IPv4协议 56. //SOCK_STREAM表示使用TCP协议 57. if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0){ 58. herror("Init socket error!"); 59. return -1; 60. } 61. bzero(&addr,sizeof(addr)); 62. addr.sin_family = AF_INET; 63. addr.sin_port = htons(serverPort); 64. addr.sin_addr.s_addr = inet_addr(server);//按IP初始化 65. 66. if(addr.sin_addr.s_addr == INADDR_NONE){//如果输入的是域名 67. phost = (struct hostent*)gethostbyname(server); 68. if(phost==NULL){ 69. herror("Init socket s_addr error!"); 70. return -1; 71. } 72. addr.sin_addr.s_addr =((struct in_addr*)phost->h_addr)->s_addr; 73. } 74. if(connect(sockfd,(struct sockaddr*)&addr, sizeof(addr))<0) 75. { 76. perror("Connect server fail!"); 77. return -1; //0表示成功,-1表示失败 78. } 79. else 80. return sockfd; 81.} 82./************************************************************** 83. * 发送消息,如果出错返回-1,否则返回发送的字符长度 84. * sockfd:socket标识,sendBuff:发送的字符串 85. * *********************************************************/ 86.int send_msg(int sockfd,char * sendBuff) 87.{ 88. int sendSize=0; 89. if((sendSize=send(sockfd,sendBuff,strlen(sendBuff),0))<=0){ 90. herror("Send msg error!"); 91. return -1; 92. }else 93. return sendSize; 94.} 95./**************************************************************** 96. *接受消息,如果出错返回NULL,否则返回接受字符串的指针(动态分配,注意释放) 97. *sockfd:socket标识 98. * *********************************************************/ 99.char* recv_msg(int sockfd){ 100. char * response; 101. int flag=0,recLenth=0; 102. response=(char *)malloc(RES_LENGTH); 103. memset(response,0,RES_LENGTH); 104. 105. for(flag=0;;) 106. { 107. printf("======recv data:/n"); 108. if(( recLenth=recv(sockfd,response+flag,RES_LENGTH-flag,0))==-1 ) 109. { 110. free(response); 111. printf("Return value : %d/n", recLenth); 112. perror("Recv msg error : "); 113. return NULL; 114. } 115. else if(recLenth==0) 116. break; 117. else 118. { 119. printf("%d char recieved data : %s./n", recLenth, response+flag); 120. flag+=recLenth; 121. recLenth=0; 122. } 123. } 124. printf("Return value : %d/n", recLenth); 125. response[flag]='/0'; 126. return response; 127.} 128./************************************************** 129. *关闭连接 130. * **********************************************/ 131.int close_socket(int sockfd) 132.{ 133. close(sockfd); 134. return 0; 135.}

     

    TCP Server 代码:

    01.#include <unistd.h> /* fork, close */ 02.#include <stdlib.h> /* exit */ 03.#include <string.h> /* strlen */ 04.#include <stdio.h> /* perror, fdopen, fgets */ 05.#include <sys/socket.h> 06.#include <sys/wait.h> /* waitpid */ 07.#include <netdb.h> /* getaddrinfo */ 08.#define die(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) 09.#define PORT "4242" 10.#define NUM_CHILDREN 3 11.#define MAXLEN 1024 12.int readline(int fd, char *buf, int maxlen); // forward declaration 13.int recvdata(int fd, char *buf, int maxlen); // forward declaration 14.int main(int argc, char** argv) 15.{ 16. int i, n, sockfd, clientfd; 17. int yes = 1; // used in setsockopt(2) 18. struct addrinfo *ai; 19. struct sockaddr_in *client; 20. socklen_t client_t; 21. pid_t cpid; // child pid 22. char line[MAXLEN]; 23. char cpid_s[32]; 24. char welcome[32]; 25. /* Create a socket and get its file descriptor -- socket(2) */ 26. sockfd = socket(AF_INET, SOCK_STREAM, 0); 27. if (sockfd == -1) { 28. die("Couldn't create a socket"); 29. } 30. /* Prevents those dreaded "Address already in use" errors */ 31. if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&yes, sizeof(int)) == -1) { 32. die("Couldn't setsockopt"); 33. } 34. /* Fill the address info struct (host + port) -- getaddrinfo(3) */ 35. if (getaddrinfo(NULL, PORT, NULL, &ai) != 0) { // get localhost 36. die("Couldn't get address"); 37. } 38. /* Assign address to this socket's fd */ 39. if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) != 0) { // only bind on localhost ip 40. die("Couldn't bind socket to address"); 41. } 42. /* Free the memory used by our address info struct */ 43. freeaddrinfo(ai); 44. /* Mark this socket as able to accept incoming connections */ 45. /* printf("Process %d Listening/n", getpid()); */ 46. if (listen(sockfd, 10) == -1) { 47. die("Couldn't make socket listen"); 48. } 49. printf("One new connection is coming!/n"); 50. /* Fork you some child processes. */ 51. for (i = 0; i < NUM_CHILDREN; i++) { 52. cpid = fork(); 53. if (cpid == -1) { 54. die("Couldn't fork"); 55. } 56. if (cpid == 0) { // We're in the child ... 57. for (;;) { // Run forever ... 58. /* Necessary initialization for accept(2) */ 59. client_t = sizeof client; 60. /* Blocks! */ 61. printf("Waiting new connection!/n"); 62. clientfd = accept(sockfd, (struct sockaddr *)&client, &client_t); 63. if (clientfd == -1) { 64. die("Couldn't accept a connection"); 65. } 66. /* Send a welcome message/prompt */ 67. bzero(cpid_s, 32); 68. bzero(welcome, 32); 69. sprintf(cpid_s, "%d", getpid()); 70. sprintf(welcome, "Child %s echo> ", cpid_s); 71. send(clientfd, welcome, strlen(welcome), 0); 72. /* Read a line from the client socket ... */ 73. /* n = readline(clientfd, line, MAXLEN); 74. if (n == -1) { 75. die("Couldn't read line from connection"); 76. } */ 77. 78. n = recvdata(clientfd, line, MAXLEN); 79. printf("recieve data: %s", line); 80. /* ... and echo it back */ 81. send(clientfd, line, n, 0); 82. /* Clean up the client socket */ 83. close(clientfd); 84. printf("Close client socket./n"); 85. } 86. } 87. } 88. /* Sit back and wait for all child processes to exit */ 89. while (waitpid(-1, NULL, 0) > 0); 90. /* Close up our socket */ 91. close(sockfd); 92. printf("Close server socket./n"); 93. return 0; 94.} 95. 96./** 97. * Simple utility function that reads a line from a file descriptor fd, 98. * up to maxlen bytes -- ripped from Unix Network Programming, Stevens. 99. */ 100.int readline(int fd, char *buf, int maxlen) 101.{ 102. int n, rc; 103. char c; 104. for (n = 1; n < maxlen; n++) { 105. if ((rc = read(fd, &c, 1)) == 1) { 106. *buf++ = c; 107. if (c == '/n') 108. break; 109. } else if (rc == 0) { 110. if (n == 1) 111. return 0; // EOF, no data read 112. else 113. break; // EOF, read some data 114. } else 115. return -1; // error 116. } 117. *buf = '/0'; // null-terminate 118. 119. return n; 120.} 121.int recvdata(int fd, char *buf, int maxlen) 122.{ 123. return recv(fd, buf, maxlen, 0); 124.}

     

     

    采用select的TCP Server:

    01.#include <stdio.h> 02.#include <stdlib.h> 03.#include <unistd.h> 04.#include <errno.h> 05.#include <string.h> 06.#include <sys/types.h> 07.#include <sys/socket.h> 08.#include <netinet/in.h> 09.#include <arpa/inet.h> 10.#define MYPORT 1234 // the port users will be connecting to 11.#define BACKLOG 5 // how many pending connections queue will hold 12.#define BUF_SIZE 1024 13.int fd_A[BACKLOG]; // accepted connection fd 14.int conn_amount; // current connection amount 15.void showclient() 16.{ 17. int i; 18. printf("client amount: %d/n", conn_amount); 19. for (i = 0; i < BACKLOG; i++) { 20. printf("[%d]:%d ", i, fd_A[i]); 21. } 22. printf("/n/n"); 23.} 24.int main(void) 25.{ 26. int sock_fd, new_fd; // listen on sock_fd, new connection on new_fd 27. struct sockaddr_in server_addr; // server address information 28. struct sockaddr_in client_addr; // connector's address information 29. socklen_t sin_size; 30. int yes = 1; 31. char buf[BUF_SIZE]; 32. int ret; 33. int i; 34. if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 35. perror("socket"); 36. exit(1); 37. } 38. if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { 39. perror("setsockopt"); 40. exit(1); 41. } 42. server_addr.sin_family = AF_INET; // host byte order 43. server_addr.sin_port = htons(MYPORT); // short, network byte order 44. server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP 45. memset(server_addr.sin_zero, '/0', sizeof(server_addr.sin_zero)); 46. if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { 47. perror("bind"); 48. exit(1); 49. } 50. if (listen(sock_fd, BACKLOG) == -1) { 51. perror("listen"); 52. exit(1); 53. } 54. printf("listen port %d/n", MYPORT); 55. fd_set fdsr; 56. int maxsock; 57. struct timeval tv; 58. conn_amount = 0; 59. sin_size = sizeof(client_addr); 60. maxsock = sock_fd; 61. while (1) 62. { 63. // initialize file descriptor set 64. FD_ZERO(&fdsr); 65. FD_SET(sock_fd, &fdsr); // add fd 66. // timeout setting 67. tv.tv_sec = 30; 68. tv.tv_usec = 0; 69. // add active connection to fd set 70. for (i = 0; i < BACKLOG; i++) { 71. if (fd_A[i] != 0) { 72. FD_SET(fd_A[i], &fdsr); 73. } 74. } 75. ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv); 76. if (ret < 0) { // error 77. perror("select"); 78. break; 79. } else if (ret == 0) { // time out 80. printf("timeout/n"); 81. continue; 82. } 83. // check every fd in the set 84. for (i = 0; i < conn_amount; i++) 85. { 86. if (FD_ISSET(fd_A[i], &fdsr)) // check which fd is ready 87. { 88. ret = recv(fd_A[i], buf, sizeof(buf), 0); 89. if (ret <= 0) 90. { // client close 91. printf("ret : %d and client[%d] close/n", ret, i); 92. close(fd_A[i]); 93. FD_CLR(fd_A[i], &fdsr); // delete fd 94. fd_A[i] = 0; 95. conn_amount--; 96. } 97. else 98. { // receive data 99. if (ret < BUF_SIZE) 100. memset(&buf[ret], '/0', 1); // add NULL('/0') 101. printf("client[%d] send:%s/n", i, buf); 102. } 103. } 104. } 105. // check whether a new connection comes 106. if (FD_ISSET(sock_fd, &fdsr)) // accept new connection 107. { 108. new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size); 109. if (new_fd <= 0) 110. { 111. perror("accept"); 112. continue; 113. } 114. // add to fd queue 115. if (conn_amount < BACKLOG) 116. { 117. fd_A[conn_amount++] = new_fd; 118. printf("new connection client[%d] %s:%d/n", conn_amount, 119. inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 120. if (new_fd > maxsock) // update the maxsock fd for select function 121. maxsock = new_fd; 122. } 123. else 124. { 125. printf("max connections arrive, exit/n"); 126. send(new_fd, "bye", 4, 0); 127. close(new_fd); 128. break; 129. } 130. } 131. showclient(); 132. } 133. // close other connections 134. for (i = 0; i < BACKLOG; i++) 135. { 136. if (fd_A[i] != 0) 137. { 138. close(fd_A[i]); 139. } 140. } 141. exit(0); 142.}

     

    PS:未采用select多路复用的TCP Server代码中,程序会在accept处阻塞,等待新的连接;

            而在使用了select的TCP Server代码中,当一个已完成的连接准备好被accept的时候,select会把监听socket标记为可读,

            再调用accept接收这个连接。

    最新回复(0)