linux多線程socket編程
『壹』 linux socket多線程
開線程的時候初始化socket方面錯誤的可能性比較大,好好調調吧
『貳』 linux下的 socket編程問題!
第一個問題:
對,是那樣的,用open打開文件,用read讀取文件,在發送給對方,接收方接收到後,寫入文件就可以了。不過在這個過程中最好別用字元串函數,除非你很熟悉。
第二個問題
首先你得去搞清楚什麼是線程,什麼是進程,fork出來的叫進程,pthread_create出來的才叫線程。伺服器有很多種模型(多進程,多線程,select,epoll模型,這個我的blog上有,famdestiny.cublog.cn),不一定要用多進程。
給你寫了個代碼,自己先看看:
注意,在自己的目錄下創建一個叫pserverb的文件,程序會把這個文件復製成test文件。你可以自己根據需要改改
server:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define SERV_PORT 5358
#define MAX_CONN 10
#define BUF_LEN 1024
void str_echo(FILE *fp, int sockfd){
ssize_t nread;
int file_fd;
char buf[BUF_LEN] = {0};
file_fd = open("test", O_WRONLY | O_TRUNC | O_CREAT, 0755);
while(1) {
bzero(buf, BUF_LEN);
if((nread = read(sockfd, buf, BUF_LEN)) == -1) {
if(errno == EINTR) {
continue;
}
else {
printf("readn error: %s\n", strerror(errno));
continue;
}
}
else if (nread == 0) {
break;
}
else {
printf("%s\n", buf);
write(file_fd, buf, nread);
}
}
close(file_fd);
}
void sig_chld(int sig){
pid_t pid;
int state;
while((pid = waitpid(-1, &state, WNOHANG)) > 0){
printf("child process %d exited.", pid);
}
return;
}
int main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t cliaddrlen;
pid_t childpid;
struct sockaddr_in servaddr, cliaddr;
if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
printf("socket error: %s\n", strerror(errno));
return 0;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1){
printf("bind error: %s\n", strerror(errno));
return 0;
}
if(listen(listenfd, MAX_CONN) == -1){
printf("listen error: %s\n", strerror(errno));
return 0;
}
signal(SIGCHLD, sig_chld);
while(1){
cliaddrlen = sizeof(cliaddr);
if((connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddrlen)) == -1){
if(errno == EINTR){
continue;
}
else{
printf("accept error: %s\n", strerror(errno));
continue;
}
}
if((childpid = fork()) == 0){
close(listenfd);
str_echo(stdin, connfd);
exit(0);
}
else if(childpid > 0){
close(connfd);
}
else{
printf("fork error!\n");
continue;
}
}
}
client:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#define SERV_ADDR "127.0.0.1"
#define SERV_PORT 5358
#define BUF_LEN 1024
void str_cli(char *path, int sockfd)
{
char sendbuf[BUF_LEN] = {0};
int fd, n;
if((fd = open("./pserverb", O_RDONLY)) == -1){
printf("%s\n", strerror(errno));
exit(0);
}
while((n = read(fd, sendbuf, BUF_LEN)) != 0) {
if(n < 0){
printf("%s\n", strerror(errno));
exit(0);
}
write(sockfd, sendbuf, n);
bzero(sendbuf, BUF_LEN);
}
close(fd);
return;
}
int main(int argc, char **argv)
{
int fd;
struct sockaddr_in servaddr;
fd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(SERV_ADDR);
servaddr.sin_port = htons(SERV_PORT);
if (connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
printf("connect error: %s\n", strerror(errno));
return 0;
}
str_cli(argv[1], fd);
return 0;
}
『叄』 Linux操作系統下Socket編程地址結構介紹
linux下的網路通信程序,一定要和一個結構打交道,這個結構就是socket
address。比如bind、connect等等函數都要使用socket
address結構。理解socket
address時我們要明白,其實在linux下針對於不同的socket
domain定義了一個通用的地址結構struct
sockaddr,它的具體定義為:
{unsigned
short
int
sa_family;char
sa_data[14];}
struct
sockaddr
其中,sa_family為調用socket()函數時的參數domain參數,sa_data為14個字元長度存儲。針對於不同domain下的socket,通用地址結構又對應了不同的定義,例如一般的AF_INET
domain下,socket
address的定義如下:
struct
sockaddr_in{unsigned
short
int
sin_family;uint16_t
sin_port;struct
in_addr
sin_addr;unsigned
char
sin_zero[8];//未使用}struct
in_addr{uint32_t
s_addr;}
當socket的domain不同於AF_INET時,具體的地址定義又是不同的,但是整個地址結構的大小、容量都是和通用地址結構一致的。
『肆』 剛介入linux c的socket編程沒多久,想要寫一個socket客戶端,實現多線程處理發送和接收,哪位大俠幫幫忙啊
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8888
void *yourfunction(void *connect_fd)
{
int connfd = *((int *)connect_fd);
。。。。
} //你沒說具體的應用,所以只能寫這么多了。在這裡面直接對connfd調用read和write函數就可以和客戶端收發數據了。
//補充:是啊 返回給客戶端什麼信息啊?
int main(void)
{
int sockfd, n, connfd;
pthread_t tid;
struct sockaddr_in servaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
perror("socket:");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
n = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (n == -1)
{
perror("bind:");
exit(1);
}
n = listen(sockfd, 20);
if (n == -1)
{
perror("listen:");
exit(1);
}
while (1)
{
connfd = accept(sockfd, (struct sockaddr *)&servaddr, NULL);
pthread_create(&tid, NULL, yourfunction, (void *)&connfd);
}
return 0;
}
『伍』 linux c socket 如何實現一個進程多個線程,每個線程管理多個socket連接
大家仔細看,樓主的題目還是很有難度的呢,一個進程多個線程容易實現,但是要讓這些線程中每個線程都管理多個socket連接,確實比較難~~坐等高手。
不過一般都是一個線程處理一個socket連接,這種例子是:
(取自書上,僅供學習,直接編譯肯定通不過,少書上其他代碼)
==================================================
/* include serv06 */#include "unpthread.h"
intmain(int argc, char **argv)
{
int listenfd, connfd;
void sig_int(int);
void *doit(void *);
pthread_t tid;
socklen_t clilen, addrlen;
struct sockaddr *cliaddr;
if (argc == 2) listenfd = Tcp_listen(NULL, argv[1], &addrlen);
else if (argc == 3)
listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
else
err_quit("usage: serv06 [ <host> ] <port#>");
cliaddr = Malloc(addrlen);
Signal(SIGINT, sig_int);
for ( ; ; ) { clilen = addrlen;
connfd = Accept(listenfd, cliaddr, &clilen);
Pthread_create(&tid, NULL, &doit, (void *) connfd); }
}
void *doit(void *arg)
{
void web_child(int);
Pthread_detach(pthread_self()); web_child((int) arg);
Close((int) arg);
return(NULL);
}
/* end serv06 */
voidsig_int(int signo)
{
void pr_cpu_time(void);
pr_cpu_time(); exit(0);
}
================================================================
『陸』 linux socket 編程
這類問題,你不用考慮太復雜的,可以直接使用socket提供的tcp服務介面,通過send和recv等函數處理就行了。數據建議自行寫封裝和解封函數,
介面類似這樣:int pack(char *, struct data *); int unpack(char *, struct data *);
可以按照你自己的喜好,將你的struct按照你的方式填入一個char*裡面(你直接將struct data*類型轉換後賦值給char*類型都行),然後就可以使用介面了;
你完全不用管tcp的實現機制的,tcp有擁塞控制,超時重傳,自動分包等機制,可以保證你的數據按准確的方式送達;
像什麼包的數據頭什麼的,如果你需要定義的是應用層的協議,或者你希望自定義網路層和傳輸層(使用raw方式的socket),你才需要考慮;
『柒』 Windows Socket和Linux Socket編程的區別
1)頭文件
windows下winsock.h/winsock2.h
linux下sys/socket.h
錯誤處理:errno.h
其他常用函數的頭文件可到命令行下用man指令查詢。
2)初始化
windows下需要用WSAStartup
linux下不需要(很方便),直接可以使用
3)關閉socket
windows下closesocket(...)
linux下close(...)
4)類型
windows下SOCKET
在linux下為int類型
5)綁定地址的結構體
名稱相同,都是struct sockaddr、struct sockaddr_in,這兩者通常轉換使用;
在Windows下面名稱都是大寫,而在Linux下為小寫
常用:
Linux下:
sockaddr_in destAddr;
destAdd.sin_family=AF_INET;
destAddr.sin_port=htons(2030);
destAddr.sin_addr.s_addr=inet_addr("192.168.1.1");
Windows下:
SOCKADDR_IN destAddr;
destAddr.sin_addr.S_un.S_addr=inet_addr("192.168.1.1");
但結構體中成員的名稱不同
Windows中結構體成員
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct sockaddr {
u_short sa_family;
char sa_data[14];
};
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
};
下面的一些宏可以使windows下的程序移植到linux下(通過類型的重新定義,使代碼具有linux和windows下的移植性)
[cpp] view plain
#ifdef WIN32
typedef int socklen_t;
typedef int ssize_t;
#endif
#ifdef __LINUX__
typedef int SOCKET;
typedef unsigned char BYTE;
typedef unsigned long DWORD;
#define FALSE 0
#define SOCKET_ERROR (-1)
#endif
6)獲取錯誤碼
windows下getlasterror()/WSAGetLastError()
linux下errno變數
7)設置非阻塞
windows下ioctlsocket()
linux下fcntl() <fcntl.h>
8)send函數最後一個參數
windows下一般設置為0
linux下最好設置為MSG_NOSIGNAL,如果不設置,在發送出錯後有可 能會導致程序退出。
9)毫秒級時間獲取
windows下GetTickCount()
linux下gettimeofday()
10)數據類型的一些轉化
通用的:
小端到大端(網路協議使用)的轉換:htonl, htons
點分十進制IP和整數之間的相互轉換:inet_addr()(該函數將點分十進制轉為整數),inet_aton(),inet_ntoa(),inet_pton()(linux下獨有 該函數可以實現相互之間的轉換)
使用到的頭文件不相同,linux下用man命令查詢。
另外注意:
linux下使用的套接字為伯克利套接字,因此在select()函數的使用上(第一個參數的設置)也有區別;
windows下為了與伯克利套接字匹配,第一個參數是無所謂,一般可設為0;
int maxfdp是一個整數值,是指集合中所有文件描述符的范圍,即所有文件描述符的最大值加1,不能錯!
3、多線程
多線程: (win)process.h --〉(linux)pthread.h
_beginthread --> pthread_create
_endthread --> pthread_exit
『捌』 linux socket 編程
去查一下select系統調用。
select的read set那個參數,可以包含一個socket和一個pipe(Linux下叫做fifo,你信號用的是fifo傳遞嗎?),反正兩個在LInux下都是「文件描述符」,同時select函數可以在最後一個參數設置超時。
這樣可以么?