C语言socket编程
建议先去看一下思路
真的写的很不错呦~
思路参考博客:https://www.cnblogs.com/renfanzi/p/5713054.html
linux c语言socket编程代码(单一服务端与客户端) 【此代码有bug,但很方便理解,用于理解使用】:
代码参考博客:https://www.cnblogs.com/xudong-bupt/p/3483059.html
服务端代码:
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <sys/shm.h> #define MYPORT 8887 #define QUEUE 20 #define BUFFER_SIZE 1024 int main() { // 实例化socket对象, 定义sockfd /* AF_INET 默认为IPv4 * SOCK_STREAM 流式socket, for TCP * 0 协议, 默认选择合适的协议 * */ int server_sockfd = socket(AF_INET, SOCK_STREAM, 0); ///定义sockaddr_in struct sockaddr_in server_sockaddr; server_sockaddr.sin_family = AF_INET; server_sockaddr.sin_port = htons(MYPORT); server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 将套接字绑定到地址 // bind,成功返回0,出错返回-1 if (bind(server_sockfd, (struct sockaddr *) &server_sockaddr, sizeof(server_sockaddr)) == -1) { perror("bind"); exit(1); } // 监听 // listen,成功返回0,出错返回-1 if (listen(server_sockfd, QUEUE) == -1) { perror("listen"); exit(1); } // 客户端套接字 char buffer[BUFFER_SIZE]; struct sockaddr_in client_addr; socklen_t length = sizeof(client_addr); // 进入阻塞状态,等待客户连接 // 成功返回非负描述字,出错返回-1 int conn = accept(server_sockfd, (struct sockaddr *) &client_addr, &length); if (conn < 0) { perror("connect"); exit(1); } // 循环 while (1) { memset(buffer, 0, sizeof(buffer)); // 接受消息 int len = recv(conn, buffer, sizeof(buffer), 0); printf("len: %d\n", len); //这里是一直循环的,如果客户端说一句话,然后结束以后,这里一直循环,需要注意 if (strcmp(buffer, "exit\n") == 0) break; fputs(buffer, stdout); // 发送消息 send(conn, "hehe", 5, 0); } close(conn); close(server_sockfd); return 0; }
客户端代码:
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <sys/shm.h> #define MYPORT 8887 #define BUFFER_SIZE 1024 int main() { ///定义sockfd int sock_cli = socket(AF_INET,SOCK_STREAM, 0); ///定义sockaddr_in struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(MYPORT); ///服务器端口 servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ///服务器ip ///连接服务器,成功返回0,错误返回-1 if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { perror("connect"); exit(1); } char sendbuf[BUFFER_SIZE]; char recvbuf[BUFFER_SIZE]; while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL) { send(sock_cli, sendbuf, strlen(sendbuf),0); ///发送 if(strcmp(sendbuf,"exit\n")==0) break; recv(sock_cli, recvbuf, sizeof(recvbuf),0); ///接收 fputs(recvbuf, stdout); memset(sendbuf, 0, sizeof(sendbuf)); memset(recvbuf, 0, sizeof(recvbuf)); } close(sock_cli); return 0; }
采用C/S架构,Tcp、Ip协议,服务器端使用共享内存的方式,不同客户端连接服务端,实现网络聊天室的功能(多用户)
服务端:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> //数据类型定义 #include <sys/stat.h> //文件属性 #include <netinet/in.h> //定义数据结构sockaddr_in #include <sys/socket.h> //提供socket函数和数据结构 #include <string.h> #include <unistd.h> #include <signal.h> #include <sys/ipc.h> #include <errno.h> #include <sys/shm.h> //共享内存 #include <time.h> #include<sys/time.h> #include <arpa/inet.h> #define PERM S_IRUSR | S_IWUSR //用户读写 #define MYPORT 8080 //通信端口 #define BACKLOG 10 //定义服务器段可以连接的最大客户数 #define MYHOST "192.168.2.137" #define WELCOME "|---------------Welcome to the chat room!----------------|"//当客户端连接服务端时,向客户端发送此字符串 //将int类型转换成char*类型 void itoa(int i, char *string) { int mask = 1; while (i / mask >= 10) mask *= 10; while (mask > 0) { *string++ = i / mask + '0'; i %= mask; mask /= 10; } *string = '\0'; } //得到当前系统的时间 void get_cur_time(char *time_str) { struct timeval now; gettimeofday(&now, NULL); strcpy(time_str, ctime(&now.tv_sec)); } //创建共享存储区 int shm_create() { int shmid; //shmid = shmget(IPC_PRIVATE, 1024, PERM); if ((shmid = shmget(IPC_PRIVATE, 1024, PERM)) == -1) { fprintf(stderr, "Create Share Memory Error:%s\n\a", strerror(errno)); exit(1); } return shmid; } //端口绑定函数。创建套接字,并绑定到指定端口 int bindPort(unsigned short int port) { int sockfd; struct sockaddr_in my_addr; sockfd = socket(AF_INET, SOCK_STREAM, 0); //创建基于流套接字 //bzero(&(my_addr.sin_zero),0); bzero(&my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET; //IPV4协议族 my_addr.sin_port = htons(port); //转换端口为网络字节序 my_addr.sin_addr.s_addr = inet_addr(MYHOST); if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) { perror("fail to bind"); exit(1); } printf("bind success!\n"); return sockfd; } int main(int argc, char *argv[]) { int sockfd, clientfd; //监听套接字、客户套接字 int sin_size, recvbytes; pid_t pid, ppid; //定义父子进程标记 char *buf, *read_addr, *write_addr, *temp, *time_str; //需要用到的缓冲区 struct sockaddr_in their_addr; //定义地址结构 int shmid; shmid = shm_create(); //创建共享存储区 temp = (char *) malloc(255); time_str = (char *) malloc(50); sockfd = bindPort(MYPORT); //绑定端口 get_cur_time(time_str); printf("Time is : %s\n", time_str); if (listen(sockfd, BACKLOG) == -1) { //在指定端口上监听 perror("fail to listen"); exit(1); } printf("listen....\n"); while (1) { /* if (listen(sockfd, BACKLOG) == -1) { perror("fail to listen"); exit(1); } */ //接受一个客户端的连接请求 if ((clientfd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size)) == -1) { perror("fail to accept"); exit(1); } //得到客户端的IP地址输出 char address[20]; inet_ntop(AF_INET, &their_addr.sin_addr, address, sizeof(address)); printf("accept from %s\n", address); send(clientfd, WELCOME, strlen(WELCOME), 0); //发送问候信息 buf = (char *) malloc(255); ppid = fork(); //创建子进程 if (ppid == 0) //子进程 { pid = fork(); //子进程创建子进程 while (1) { if (pid > 0) { //buf = (char *)malloc(255); //父进程用于接收信息 memset(buf, 0, 255); printf("OK\n"); if ((recvbytes = recv(clientfd, buf, 255, 0)) <= 0) { perror("fail to recv"); close(clientfd); raise(SIGKILL); exit(1); } write_addr = shmat(shmid, 0, 0); //shmat将shmid所代表的全局的共享存储区关联到本进程的进程空间 memset(write_addr, '\0', 1024); //把接收到的消息存入共享存储区中 strncpy(write_addr, buf, 1024); //把接收到的消息连接此刻的时间字符串输出到标准输出 get_cur_time(time_str); strcat(buf, time_str); printf(" %s\n", buf); } else if (pid == 0) { //子进程用于发送消息 sleep(1); //子进程先等待父进程把接收到的信息存入共享存储区 read_addr = shmat(shmid, 0, 0); //读取共享存储区的内容 //temp存储上次读取过的内容,每次先判断是否已经读取过该消息 if (strcmp(temp, read_addr) != 0) { strcpy(temp, read_addr); //更新temp,表示已经读取过该消息 get_cur_time(time_str); strcat(read_addr, time_str); if (send(clientfd, read_addr, strlen(read_addr), 0) == -1) { perror("fail to send"); exit(1); } memset(read_addr, '\0', 1024); strcpy(read_addr, temp); } } else perror("fai to fork"); } } } printf("------------------------------------\n"); free(buf); close(sockfd); close(clientfd); return 0; }
客户端二、客户端三...
#include <stdio.h> #include <netinet/in.h> //定义数据结构sockaddr_in #include <sys/socket.h> //定义socket函数以及数据结构 #include <sys/types.h> #include <string.h> #include <stdlib.h> #include <netdb.h> #include <unistd.h> #include <signal.h> #include <time.h> #include <netinet/in.h> #include <arpa/inet.h> #define MYPORT 8080 #define MYHOST "192.168.2.137" int main(int argc, char *argv[]) { struct sockaddr_in clientaddr; //定义地址结构 pid_t pid; int clientfd, sendbytes, recvbytes; struct hostent *host; //主机信息数据结构 char *buf, *buf_read; // if (argc < 4) // { // printf("wrong usage"); // printf("%s host port name\n", argv[0]); // exit(1); // } // host = gethostbyname(argv[1]); if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("fail to create socket"); exit(1); } bzero(&clientaddr, sizeof(clientaddr)); clientaddr.sin_family = AF_INET; clientaddr.sin_port = htons(MYPORT); clientaddr.sin_addr.s_addr = inet_addr(MYHOST); //客户端连接服务端 if (connect(clientfd, (struct sockaddr *)&clientaddr, sizeof(struct sockaddr)) == -1) { perror("fail to connect"); exit(1); } buf = (char *)malloc(120); memset(buf, 0, 120); buf_read = (char *)malloc(100); if (recv(clientfd, buf, 100, 0) == -1) { perror("fail to recv"); exit(1); } printf("\n%s\n", buf); pid = fork(); while (1) { if (pid > 0) { //父进程发送消息 strcpy(buf, "afsasdf"); strcat(buf, ":"); memset(buf_read, 0, 100); fgets(buf_read, 100, stdin); strncat(buf, buf_read, strlen(buf_read) - 1); if ((sendbytes = send(clientfd, buf, strlen(buf), 0)) == -1) { perror("fail to send"); exit(1); } } else if (pid == 0) { //子进程接受消息 memset(buf, 0, 100); if (recv(clientfd, buf, 100, 0) <= 0) { perror("fail to recv"); close(clientfd); raise(SIGSTOP); exit(1); } printf("%s\n", buf); } else perror("fork error"); } close(clientfd); return 0; }
作者:沐禹辰
出处:http://www.cnblogs.com/renfanzi/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
出处:http://www.cnblogs.com/renfanzi/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。